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