001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.impl; 018 019import java.util.Optional; 020 021import org.apache.camel.NamedNode; 022import org.apache.camel.impl.engine.DefaultNodeIdFactory; 023import org.apache.camel.model.FromDefinition; 024import org.apache.camel.model.RouteDefinition; 025import org.apache.camel.model.rest.RestDefinition; 026import org.apache.camel.model.rest.VerbDefinition; 027import org.apache.camel.spi.NodeIdFactory; 028 029/** 030 * Factory for generating route ids based on uris. 031 * <p> 032 * For direct/seda routes it returns route name (direct:start -> start). For 033 * rest routes it returns its method and context path formatted as one string. 034 * <p> 035 * When id cannot be generated, falls back to other {@link NodeIdFactory} 036 * implementation. If none is passed in the constructor, then 037 * {@link DefaultNodeIdFactory} is used. 038 */ 039public class RouteIdFactory implements NodeIdFactory { 040 041 private static final char SEPARATOR = '-'; 042 private NodeIdFactory defaultNodeIdFactory; 043 044 public RouteIdFactory() { 045 defaultNodeIdFactory = new DefaultNodeIdFactory(); 046 } 047 048 public RouteIdFactory(NodeIdFactory defaultNodeIdFactory) { 049 this.defaultNodeIdFactory = defaultNodeIdFactory; 050 } 051 052 @Override 053 public String createId(NamedNode definition) { 054 if (definition instanceof RouteDefinition) { 055 Optional<String> id = extractId((RouteDefinition)definition); 056 057 if (id.isPresent()) { 058 return id.get(); 059 } 060 061 id = extractIdFromRestDefinition((RouteDefinition)definition); 062 063 if (id.isPresent()) { 064 return id.get(); 065 } 066 } 067 068 if (definition instanceof VerbDefinition) { 069 Optional<String> id = extractIdFromVerb((VerbDefinition)definition); 070 071 if (id.isPresent()) { 072 return id.get(); 073 } 074 } 075 076 return defaultNodeIdFactory.createId(definition); 077 } 078 079 /** 080 * Extract id from routes 081 */ 082 private Optional<String> extractId(RouteDefinition routeDefinition) { 083 if (routeDefinition.getRestDefinition() != null) { 084 return Optional.empty(); 085 } 086 087 if (routeDefinition.getInput() == null) { 088 return Optional.empty(); 089 } 090 091 FromDefinition from = routeDefinition.getInput(); 092 String uri = from.getEndpointUri(); 093 094 // we want to use the context-path of the route 095 int colon = uri.indexOf(':'); 096 097 if (colon > 0) { 098 String name = uri.substring(colon + 1); 099 100 int questionMark = name.indexOf("?"); 101 102 if (questionMark > 0) { 103 return Optional.of(name.substring(0, questionMark)); 104 } else { 105 return Optional.of(name); 106 } 107 } 108 109 return Optional.empty(); 110 } 111 112 /** 113 * Extract id from a rest route. 114 */ 115 private Optional<String> extractIdFromRestDefinition(RouteDefinition route) { 116 if (route.getRestDefinition() != null) { 117 return extractIdFromInput(route); 118 } 119 120 return Optional.empty(); 121 } 122 123 /** 124 * Extract id from a rest verb definition. 125 */ 126 private Optional<String> extractIdFromVerb(VerbDefinition verb) { 127 RestDefinition restDefinition = verb.getRest(); 128 129 if (restDefinition != null) { 130 StringBuilder routeId = new StringBuilder(); 131 routeId.append(verb.asVerb()); 132 appendWithSeparator(routeId, prepareUri(restDefinition.getPath())); 133 134 if (verb.getUri() != null && verb.getUri().length() > 0) { 135 appendWithSeparator(routeId, prepareUri(verb.getUri())); 136 } 137 138 verb.setUsedForGeneratingNodeId(true); 139 140 return Optional.of(routeId.toString()); 141 } 142 143 return Optional.empty(); 144 145 } 146 147 /** 148 * Extract id from rest input uri. 149 */ 150 private Optional<String> extractIdFromInput(RouteDefinition route) { 151 if (route.getInput() == null) { 152 return Optional.empty(); 153 } 154 155 FromDefinition from = route.getInput(); 156 String uri = from.getEndpointUri(); 157 158 String[] uriSplitted = uri.split(":"); 159 160 // needs to have at least 3 fields 161 if (uriSplitted.length < 3) { 162 return Optional.empty(); 163 } 164 165 String verb = uriSplitted[1]; 166 String contextPath = uriSplitted[2]; 167 String additionalUri = ""; 168 169 if (uriSplitted.length > 3 && uriSplitted[3].startsWith("/")) { 170 additionalUri = uriSplitted[3]; 171 } 172 173 StringBuilder routeId = new StringBuilder(verb.length() + contextPath.length() + additionalUri.length()); 174 175 routeId.append(verb); 176 appendWithSeparator(routeId, prepareUri(contextPath)); 177 178 if (additionalUri.length() > 0) { 179 appendWithSeparator(routeId, prepareUri(additionalUri)); 180 } 181 182 return Optional.of(routeId.toString()); 183 } 184 185 /** 186 * Prepares uri to be part of the id. 187 */ 188 private String prepareUri(String uri) { 189 if (uri == null) { 190 return ""; 191 } 192 193 if (uri.contains("?")) { 194 uri = uri.substring(0, uri.indexOf('?')); 195 } 196 197 return uri.replaceAll("/", String.valueOf(SEPARATOR)); 198 } 199 200 /** 201 * Appends new element to the builder. 202 */ 203 private void appendWithSeparator(StringBuilder builder, String str) { 204 if (builder.charAt(builder.length() - 1) == SEPARATOR) { 205 if (str.startsWith(String.valueOf(SEPARATOR))) { 206 builder.append(str.replaceFirst(String.valueOf(SEPARATOR), "")); 207 } else { 208 builder.append(str); 209 } 210 } else { 211 if (!str.startsWith(String.valueOf(SEPARATOR))) { 212 builder.append(SEPARATOR); 213 } 214 215 builder.append(str); 216 } 217 } 218}