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