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.List; 020import java.util.Optional; 021 022import org.apache.camel.NamedNode; 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). 033 * For 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} implementation. 036 * If none is passed in the constructor, then {@link DefaultNodeIdFactory} is used. 037 */ 038public class RouteIdFactory implements NodeIdFactory { 039 040 private static final char SEPARATOR = '-'; 041 private NodeIdFactory defaultNodeIdFactory; 042 043 public RouteIdFactory() { 044 defaultNodeIdFactory = new DefaultNodeIdFactory(); 045 } 046 047 public RouteIdFactory(NodeIdFactory defaultNodeIdFactory) { 048 this.defaultNodeIdFactory = defaultNodeIdFactory; 049 } 050 051 @Override 052 public String createId(NamedNode definition) { 053 if (definition instanceof RouteDefinition) { 054 Optional<String> id = extractId((RouteDefinition) definition); 055 056 if (id.isPresent()) { 057 return id.get(); 058 } 059 060 id = extractIdFromRestDefinition((RouteDefinition) definition); 061 062 if (id.isPresent()) { 063 return id.get(); 064 } 065 } 066 067 if (definition instanceof VerbDefinition) { 068 Optional<String> id = extractIdFromVerb((VerbDefinition) definition); 069 070 if (id.isPresent()) { 071 return id.get(); 072 } 073 } 074 075 return defaultNodeIdFactory.createId(definition); 076 } 077 078 /** 079 * Extract id from routes 080 */ 081 private Optional<String> extractId(RouteDefinition routeDefinition) { 082 if (routeDefinition.getRestDefinition() != null) { 083 return Optional.empty(); 084 } 085 086 List<FromDefinition> inputs = routeDefinition.getInputs(); 087 088 if (inputs == null || inputs.isEmpty()) { 089 return Optional.empty(); 090 } 091 092 FromDefinition from = inputs.get(0); 093 String uri = from.getUri(); 094 095 // we want to use the context-path of the route 096 int colon = uri.indexOf(':'); 097 098 if (colon > 0) { 099 String name = uri.substring(colon + 1); 100 101 int questionMark = name.indexOf("?"); 102 103 if (questionMark > 0) { 104 return Optional.of(name.substring(0, questionMark)); 105 } else { 106 return Optional.of(name); 107 } 108 } 109 110 return Optional.empty(); 111 } 112 113 /** 114 * Extract id from a rest route. 115 */ 116 private Optional<String> extractIdFromRestDefinition(RouteDefinition route) { 117 if (route.getRestDefinition() != null) { 118 return extractIdFromInput(route); 119 } 120 121 return Optional.empty(); 122 } 123 124 /** 125 * Extract id from a rest verb definition. 126 */ 127 private Optional<String> extractIdFromVerb(VerbDefinition verb) { 128 RestDefinition restDefinition = verb.getRest(); 129 130 if (restDefinition != null) { 131 StringBuilder routeId = new StringBuilder(); 132 routeId.append(verb.asVerb()); 133 appendWithSeparator(routeId, prepareUri(restDefinition.getPath())); 134 135 if (verb.getUri() != null && verb.getUri().length() > 0) { 136 appendWithSeparator(routeId, prepareUri(verb.getUri())); 137 } 138 139 verb.setUsedForGeneratingNodeId(true); 140 141 return Optional.of(routeId.toString()); 142 } 143 144 return Optional.empty(); 145 146 } 147 148 /** 149 * Extract id from rest input uri. 150 */ 151 private Optional<String> extractIdFromInput(RouteDefinition route) { 152 List<FromDefinition> inputs = route.getInputs(); 153 154 if (inputs == null || inputs.isEmpty()) { 155 return Optional.empty(); 156 } 157 158 FromDefinition from = inputs.get(0); 159 String uri = from.getUri(); 160 161 String[] uriSplitted = uri.split(":"); 162 163 // needs to have at least 3 fields 164 if (uriSplitted.length < 3) { 165 return Optional.empty(); 166 } 167 168 String verb = uriSplitted[1]; 169 String contextPath = uriSplitted[2]; 170 String additionalUri = ""; 171 172 if (uriSplitted.length > 3 && uriSplitted[3].startsWith("/")) { 173 additionalUri = uriSplitted[3]; 174 } 175 176 StringBuilder routeId = new StringBuilder(verb.length() + contextPath.length() + additionalUri.length()); 177 178 routeId.append(verb); 179 appendWithSeparator(routeId, prepareUri(contextPath)); 180 181 if (additionalUri.length() > 0) { 182 appendWithSeparator(routeId, prepareUri(additionalUri)); 183 } 184 185 return Optional.of(routeId.toString()); 186 } 187 188 /** 189 * Prepares uri to be part of the id. 190 */ 191 private String prepareUri(String uri) { 192 if (uri == null) { 193 return ""; 194 } 195 196 if (uri.contains("?")) { 197 uri = uri.substring(0, uri.indexOf('?')); 198 } 199 200 return uri.replaceAll("/", String.valueOf(SEPARATOR)); 201 } 202 203 /** 204 * Appends new element to the builder. 205 */ 206 private void appendWithSeparator(StringBuilder builder, String str) { 207 if (builder.charAt(builder.length() - 1) == SEPARATOR) { 208 if (str.startsWith(String.valueOf(SEPARATOR))) { 209 builder.append(str.replaceFirst(String.valueOf(SEPARATOR), "")); 210 } else { 211 builder.append(str); 212 } 213 } else { 214 if (!str.startsWith(String.valueOf(SEPARATOR))) { 215 builder.append(SEPARATOR); 216 } 217 218 builder.append(str); 219 } 220 } 221}