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.validator.ValidatorKey; 030import org.apache.camel.model.validator.ValidatorDefinition; 031import org.apache.camel.spi.DataType; 032import org.apache.camel.spi.Validator; 033import org.apache.camel.spi.ValidatorRegistry; 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.ValidatorRegistry}. 041 */ 042public class DefaultValidatorRegistry extends LRUCache<ValidatorKey, Validator> implements ValidatorRegistry<ValidatorKey> { 043 private static final long serialVersionUID = 1L; 044 private ConcurrentMap<ValidatorKey, Validator> staticMap; 045 private final CamelContext context; 046 047 public DefaultValidatorRegistry(CamelContext context) throws Exception { 048 this(context, new ArrayList<>()); 049 } 050 051 public DefaultValidatorRegistry(CamelContext context, List<ValidatorDefinition> definitions) throws Exception { 052 // do not stop on eviction, as the validator may still be in use 053 super(CamelContextHelper.getMaximumValidatorCacheSize(context), CamelContextHelper.getMaximumValidatorCacheSize(context), false); 054 // static map to hold validator we do not want to be evicted 055 this.staticMap = new ConcurrentHashMap<>(); 056 this.context = context; 057 058 for (ValidatorDefinition def : definitions) { 059 Validator validator = def.createValidator(context); 060 context.addService(validator); 061 put(new ValidatorKey(new DataType(def.getType())), validator); 062 } 063 } 064 065 public Validator resolveValidator(ValidatorKey key) { 066 Validator answer = get(key); 067 if (answer == null && ObjectHelper.isNotEmpty(key.getType().getName())) { 068 answer = get(new ValidatorKey(new DataType(key.getType().getModel()))); 069 } 070 return answer; 071 } 072 073 @Override 074 public void start() throws Exception { 075 resetStatistics(); 076 } 077 078 @Override 079 public Validator get(Object o) { 080 // try static map first 081 Validator answer = staticMap.get(o); 082 if (answer == null) { 083 answer = super.get(o); 084 } else { 085 hits.increment(); 086 } 087 return answer; 088 } 089 090 @Override 091 public Validator put(ValidatorKey key, Validator validator) { 092 // at first we must see if the key already exists and then replace it back, so it stays the same spot 093 Validator answer = staticMap.remove(key); 094 if (answer != null) { 095 // replace existing 096 staticMap.put(key, validator); 097 return answer; 098 } 099 100 answer = super.remove(key); 101 if (answer != null) { 102 // replace existing 103 super.put(key, validator); 104 return answer; 105 } 106 107 // we want validators to be static if they are part of setting up or starting routes 108 if (context.isSetupRoutes() || context.isStartingRoutes()) { 109 answer = staticMap.put(key, validator); 110 } else { 111 answer = super.put(key, validator); 112 } 113 114 return answer; 115 } 116 117 @Override 118 public void putAll(Map<? extends ValidatorKey, ? extends Validator> map) { 119 // need to use put instead of putAll to ensure the entries gets added to either static or dynamic map 120 for (Map.Entry<? extends ValidatorKey, ? extends Validator> entry : map.entrySet()) { 121 put(entry.getKey(), entry.getValue()); 122 } 123 } 124 125 @Override 126 public boolean containsKey(Object o) { 127 return staticMap.containsKey(o) || super.containsKey(o); 128 } 129 130 @Override 131 public boolean containsValue(Object o) { 132 return staticMap.containsValue(o) || super.containsValue(o); 133 } 134 135 @Override 136 public int size() { 137 return staticMap.size() + super.size(); 138 } 139 140 public int staticSize() { 141 return staticMap.size(); 142 } 143 144 @Override 145 public int dynamicSize() { 146 return super.size(); 147 } 148 149 @Override 150 public boolean isEmpty() { 151 return staticMap.isEmpty() && super.isEmpty(); 152 } 153 154 @Override 155 public Validator remove(Object o) { 156 Validator answer = staticMap.remove(o); 157 if (answer == null) { 158 answer = super.remove(o); 159 } 160 return answer; 161 } 162 163 @Override 164 public void clear() { 165 staticMap.clear(); 166 super.clear(); 167 } 168 169 @Override 170 public Set<ValidatorKey> keySet() { 171 Set<ValidatorKey> answer = new LinkedHashSet<>(); 172 answer.addAll(staticMap.keySet()); 173 answer.addAll(super.keySet()); 174 return answer; 175 } 176 177 @Override 178 public Collection<Validator> values() { 179 Collection<Validator> answer = new ArrayList<>(); 180 answer.addAll(staticMap.values()); 181 answer.addAll(super.values()); 182 return answer; 183 } 184 185 @Override 186 public Set<Entry<ValidatorKey, Validator>> entrySet() { 187 Set<Entry<ValidatorKey, Validator>> answer = new LinkedHashSet<>(); 188 answer.addAll(staticMap.entrySet()); 189 answer.addAll(super.entrySet()); 190 return answer; 191 } 192 193 @Override 194 public int getMaximumCacheSize() { 195 return super.getMaxCacheSize(); 196 } 197 198 /** 199 * Purges the cache 200 */ 201 @Override 202 public void purge() { 203 // only purge the dynamic part 204 super.clear(); 205 } 206 207 @Override 208 public boolean isStatic(DataType type) { 209 return staticMap.containsKey(new ValidatorKey(type)); 210 } 211 212 @Override 213 public boolean isDynamic(DataType type) { 214 return super.containsKey(new ValidatorKey(type)); 215 } 216 217 @Override 218 public void stop() throws Exception { 219 ServiceHelper.stopServices(staticMap.values()); 220 ServiceHelper.stopServices(values()); 221 purge(); 222 } 223 224 @Override 225 public String toString() { 226 return "ValidatorRegistry for " + context.getName() + ", capacity: " + getMaxCacheSize(); 227 } 228 229}