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