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