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.ArrayList; 020import java.util.Collection; 021import java.util.LinkedHashSet; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025import java.util.concurrent.ConcurrentHashMap; 026import java.util.concurrent.ConcurrentMap; 027 028import org.apache.camel.CamelContext; 029import org.apache.camel.Endpoint; 030import org.apache.camel.impl.transformer.TransformerKey; 031import org.apache.camel.model.transformer.TransformerDefinition; 032import org.apache.camel.spi.DataType; 033import org.apache.camel.spi.EndpointRegistry; 034import org.apache.camel.spi.Transformer; 035import org.apache.camel.spi.TransformerRegistry; 036import org.apache.camel.util.CamelContextHelper; 037import org.apache.camel.util.LRUCache; 038import org.apache.camel.util.ObjectHelper; 039import org.apache.camel.util.ServiceHelper; 040 041/** 042 * Default implementation of {@link org.apache.camel.spi.TransformerRegistry}. 043 */ 044public class DefaultTransformerRegistry extends LRUCache<TransformerKey, Transformer> implements TransformerRegistry<TransformerKey> { 045 private static final long serialVersionUID = 1L; 046 private ConcurrentMap<TransformerKey, Transformer> staticMap; 047 private ConcurrentMap<TransformerKey, TransformerKey> aliasMap; 048 private final CamelContext context; 049 050 public DefaultTransformerRegistry(CamelContext context) throws Exception { 051 this(context, new ArrayList<>()); 052 } 053 054 public DefaultTransformerRegistry(CamelContext context, List<TransformerDefinition> definitions) throws Exception { 055 // do not stop on eviction, as the transformer may still be in use 056 super(CamelContextHelper.getMaximumTransformerCacheSize(context), CamelContextHelper.getMaximumTransformerCacheSize(context), false); 057 // static map to hold transformers we do not want to be evicted 058 this.staticMap = new ConcurrentHashMap<>(); 059 this.aliasMap = new ConcurrentHashMap<>(); 060 this.context = context; 061 062 for (TransformerDefinition def : definitions) { 063 Transformer transformer = def.createTransformer(context); 064 context.addService(transformer); 065 put(createKey(def), transformer); 066 } 067 } 068 069 @Override 070 public Transformer resolveTransformer(TransformerKey key) { 071 if (ObjectHelper.isEmpty(key.getScheme()) && key.getTo() == null) { 072 return null; 073 } 074 075 // try exact match 076 Transformer answer = get(aliasMap.containsKey(key) ? aliasMap.get(key) : key); 077 if (answer != null || ObjectHelper.isNotEmpty(key.getScheme())) { 078 return answer; 079 } 080 081 // try wildcard match for next - add an alias if matched 082 TransformerKey alias = null; 083 if (key.getFrom() != null && ObjectHelper.isNotEmpty(key.getFrom().getName())) { 084 alias = new TransformerKey(new DataType(key.getFrom().getModel()), key.getTo()); 085 answer = get(alias); 086 } 087 if (answer == null && ObjectHelper.isNotEmpty(key.getTo().getName())) { 088 alias = new TransformerKey(key.getFrom(), new DataType(key.getTo().getModel())); 089 answer = get(alias); 090 } 091 if (answer == null && key.getFrom() != null && ObjectHelper.isNotEmpty(key.getFrom().getName()) 092 && ObjectHelper.isNotEmpty(key.getTo().getName())) { 093 alias = new TransformerKey(new DataType(key.getFrom().getModel()), new DataType(key.getTo().getModel())); 094 answer = get(alias); 095 } 096 if (answer == null && key.getFrom() != null) { 097 alias = new TransformerKey(key.getFrom().getModel()); 098 answer = get(alias); 099 } 100 if (answer == null) { 101 alias = new TransformerKey(key.getTo().getModel()); 102 answer = get(alias); 103 } 104 if (answer != null) { 105 aliasMap.put(key, alias); 106 } 107 108 return answer; 109 } 110 111 @Override 112 public void start() throws Exception { 113 resetStatistics(); 114 } 115 116 @Override 117 public Transformer get(Object o) { 118 // try static map first 119 Transformer answer = staticMap.get(o); 120 if (answer == null) { 121 answer = super.get(o); 122 } else { 123 hits.incrementAndGet(); 124 } 125 return answer; 126 } 127 128 @Override 129 public Transformer put(TransformerKey key, Transformer transformer) { 130 // at first we must see if the key already exists and then replace it back, so it stays the same spot 131 Transformer answer = staticMap.remove(key); 132 if (answer != null) { 133 // replace existing 134 staticMap.put(key, transformer); 135 return answer; 136 } 137 138 answer = super.remove(key); 139 if (answer != null) { 140 // replace existing 141 super.put(key, transformer); 142 return answer; 143 } 144 145 // we want transformers to be static if they are part of setting up or starting routes 146 if (context.isSetupRoutes() || context.isStartingRoutes()) { 147 answer = staticMap.put(key, transformer); 148 } else { 149 answer = super.put(key, transformer); 150 } 151 152 return answer; 153 } 154 155 @Override 156 public void putAll(Map<? extends TransformerKey, ? extends Transformer> map) { 157 // need to use put instead of putAll to ensure the entries gets added to either static or dynamic map 158 for (Map.Entry<? extends TransformerKey, ? extends Transformer> entry : map.entrySet()) { 159 put(entry.getKey(), entry.getValue()); 160 } 161 } 162 163 @Override 164 public boolean containsKey(Object o) { 165 return staticMap.containsKey(o) || super.containsKey(o); 166 } 167 168 @Override 169 public boolean containsValue(Object o) { 170 return staticMap.containsValue(o) || super.containsValue(o); 171 } 172 173 @Override 174 public int size() { 175 return staticMap.size() + super.size(); 176 } 177 178 public int staticSize() { 179 return staticMap.size(); 180 } 181 182 @Override 183 public int dynamicSize() { 184 return super.size(); 185 } 186 187 @Override 188 public boolean isEmpty() { 189 return staticMap.isEmpty() && super.isEmpty(); 190 } 191 192 @Override 193 public Transformer remove(Object o) { 194 Transformer answer = staticMap.remove(o); 195 if (answer == null) { 196 answer = super.remove(o); 197 } 198 return answer; 199 } 200 201 @Override 202 public void clear() { 203 staticMap.clear(); 204 super.clear(); 205 } 206 207 @Override 208 public Set<TransformerKey> keySet() { 209 Set<TransformerKey> answer = new LinkedHashSet<>(); 210 answer.addAll(staticMap.keySet()); 211 answer.addAll(super.keySet()); 212 return answer; 213 } 214 215 @Override 216 public Collection<Transformer> values() { 217 Collection<Transformer> answer = new ArrayList<>(); 218 answer.addAll(staticMap.values()); 219 answer.addAll(super.values()); 220 return answer; 221 } 222 223 @Override 224 public Set<Entry<TransformerKey, Transformer>> entrySet() { 225 Set<Entry<TransformerKey, Transformer>> answer = new LinkedHashSet<>(); 226 answer.addAll(staticMap.entrySet()); 227 answer.addAll(super.entrySet()); 228 return answer; 229 } 230 231 @Override 232 public int getMaximumCacheSize() { 233 return super.getMaxCacheSize(); 234 } 235 236 /** 237 * Purges the cache 238 */ 239 @Override 240 public void purge() { 241 // only purge the dynamic part 242 super.clear(); 243 } 244 245 @Override 246 public boolean isStatic(String scheme) { 247 return staticMap.containsKey(new TransformerKey(scheme)); 248 } 249 250 @Override 251 public boolean isStatic(DataType from, DataType to) { 252 return staticMap.containsKey(new TransformerKey(from, to)); 253 } 254 255 @Override 256 public boolean isDynamic(String scheme) { 257 return super.containsKey(new TransformerKey(scheme)); 258 } 259 260 @Override 261 public boolean isDynamic(DataType from, DataType to) { 262 return super.containsKey(new TransformerKey(from, to)); 263 } 264 265 @Override 266 public void stop() throws Exception { 267 ServiceHelper.stopServices(staticMap.values()); 268 ServiceHelper.stopServices(values()); 269 purge(); 270 } 271 272 @Override 273 public String toString() { 274 return "TransformerRegistry for " + context.getName() + ", capacity: " + getMaxCacheSize(); 275 } 276 277 private TransformerKey createKey(TransformerDefinition def) { 278 return ObjectHelper.isNotEmpty(def.getScheme()) ? new TransformerKey(def.getScheme()) 279 : new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType())); 280 } 281 282}