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.model; 018 019import java.io.ByteArrayInputStream; 020import java.io.ByteArrayOutputStream; 021import java.util.ArrayList; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import javax.xml.bind.JAXBContext; 027import javax.xml.bind.JAXBException; 028import javax.xml.bind.Marshaller; 029import javax.xml.bind.Unmarshaller; 030 031import org.apache.camel.model.language.NamespaceAwareExpression; 032import org.apache.camel.util.CamelContextHelper; 033import org.apache.camel.util.ObjectHelper; 034 035/** 036 * Helper for {@link RouteContextRefDefinition}. 037 */ 038public final class RouteContextRefDefinitionHelper { 039 040 private static JAXBContext jaxbContext; 041 042 private RouteContextRefDefinitionHelper() { 043 } 044 045 /** 046 * Lookup the routes from the {@link RouteContextRefDefinition}. 047 * <p/> 048 * This implementation must be used to lookup the routes as it performs a deep clone of the routes 049 * as a {@link RouteContextRefDefinition} can be re-used with multiple {@link ModelCamelContext} and each 050 * context should have their own instances of the routes. This is to ensure no side-effects and sharing 051 * of instances between the contexts. For example such as property placeholders may be context specific 052 * so the routes should not use placeholders from another {@link ModelCamelContext}. 053 * 054 * @param camelContext the CamelContext 055 * @param ref the id of the {@link RouteContextRefDefinition} to lookup and get the routes. 056 * @return the routes. 057 */ 058 @SuppressWarnings("unchecked") 059 public static synchronized List<RouteDefinition> lookupRoutes(ModelCamelContext camelContext, String ref) { 060 ObjectHelper.notNull(camelContext, "camelContext"); 061 ObjectHelper.notNull(ref, "ref"); 062 063 List<RouteDefinition> answer = CamelContextHelper.lookup(camelContext, ref, List.class); 064 if (answer == null) { 065 throw new IllegalArgumentException("Cannot find RouteContext with id " + ref); 066 } 067 068 // must clone the route definitions as they can be reused with multiple CamelContexts 069 // and they would need their own instances of the definitions to not have side effects among 070 // the CamelContext - for example property placeholder resolutions etc. 071 List<RouteDefinition> clones = new ArrayList<RouteDefinition>(answer.size()); 072 try { 073 JAXBContext jaxb = getOrCreateJAXBContext(camelContext); 074 for (RouteDefinition def : answer) { 075 RouteDefinition clone = cloneRouteDefinition(jaxb, def); 076 if (clone != null) { 077 clones.add(clone); 078 } 079 } 080 } catch (Exception e) { 081 throw ObjectHelper.wrapRuntimeCamelException(e); 082 } 083 084 return clones; 085 } 086 087 private static synchronized JAXBContext getOrCreateJAXBContext(final ModelCamelContext camelContext) throws JAXBException { 088 if (jaxbContext == null) { 089 jaxbContext = camelContext.getModelJAXBContextFactory().newJAXBContext(); 090 } 091 return jaxbContext; 092 } 093 094 private static RouteDefinition cloneRouteDefinition(JAXBContext jaxbContext, RouteDefinition def) throws JAXBException { 095 Marshaller marshal = jaxbContext.createMarshaller(); 096 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 097 marshal.marshal(def, bos); 098 099 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 100 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 101 Object clone = unmarshaller.unmarshal(bis); 102 103 if (clone instanceof RouteDefinition) { 104 RouteDefinition def2 = (RouteDefinition) clone; 105 106 // need to clone the namespaces also as they are not JAXB marshalled (as they are transient) 107 Iterator<ExpressionNode> it = ProcessorDefinitionHelper.filterTypeInOutputs(def.getOutputs(), ExpressionNode.class); 108 Iterator<ExpressionNode> it2 = ProcessorDefinitionHelper.filterTypeInOutputs(def2.getOutputs(), ExpressionNode.class); 109 while (it.hasNext() && it2.hasNext()) { 110 ExpressionNode node = it.next(); 111 ExpressionNode node2 = it2.next(); 112 113 NamespaceAwareExpression name = null; 114 NamespaceAwareExpression name2 = null; 115 if (node.getExpression() instanceof NamespaceAwareExpression) { 116 name = (NamespaceAwareExpression) node.getExpression(); 117 } 118 if (node2.getExpression() instanceof NamespaceAwareExpression) { 119 name2 = (NamespaceAwareExpression) node2.getExpression(); 120 } 121 122 if (name != null && name2 != null && name.getNamespaces() != null && !name.getNamespaces().isEmpty()) { 123 Map<String, String> map = new HashMap<String, String>(); 124 map.putAll(name.getNamespaces()); 125 name2.setNamespaces(map); 126 } 127 } 128 129 return def2; 130 } 131 132 return null; 133 } 134 135}