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