View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.extensions.validator.core.storage;
20  
21  import org.apache.myfaces.extensions.validator.core.ExtValCoreConfiguration;
22  import org.apache.myfaces.extensions.validator.internal.UsageInformation;
23  import org.apache.myfaces.extensions.validator.internal.ToDo;
24  import org.apache.myfaces.extensions.validator.internal.Priority;
25  import static org.apache.myfaces.extensions.validator.internal.UsageCategory.INTERNAL;
26  import org.apache.myfaces.extensions.validator.core.property.PropertyInformation;
27  import org.apache.myfaces.extensions.validator.core.property.PropertyDetails;
28  import org.apache.myfaces.extensions.validator.core.property.PropertyInformationKeys;
29  import org.apache.myfaces.extensions.validator.core.property.DefaultPropertyInformation;
30  import org.apache.myfaces.extensions.validator.core.metadata.MetaDataEntry;
31  import org.apache.myfaces.extensions.validator.core.CustomInformation;
32  import org.apache.myfaces.extensions.validator.core.ExtValContext;
33  import org.apache.myfaces.extensions.validator.util.ClassUtils;
34  import org.apache.myfaces.extensions.validator.util.ProxyUtils;
35  import org.apache.myfaces.extensions.validator.util.NullValueAwareConcurrentHashMap;
36  
37  import java.util.Map;
38  import java.util.List;
39  import java.util.ArrayList;
40  import java.util.concurrent.ConcurrentHashMap;
41  import java.util.concurrent.CopyOnWriteArrayList;
42  import java.util.logging.Logger;
43  
44  /**
45   * @since x.x.3
46   */
47  @UsageInformation(INTERNAL)
48  public class DefaultMetaDataStorage implements MetaDataStorage
49  {
50      protected final Logger logger = Logger.getLogger(getClass().getName());
51  
52      private Map<String, Map<String, PropertyInformation>> cachedPropertyInformation =
53              new ConcurrentHashMap<String, Map<String, PropertyInformation>>();
54  
55      private List<MetaDataStorageFilter> metaDataStorageFilters = new CopyOnWriteArrayList<MetaDataStorageFilter>();
56      private List<Class<? extends MetaDataStorageFilter>> deniedMetaDataFilters =
57              new CopyOnWriteArrayList<Class<? extends MetaDataStorageFilter>>();
58  
59      public DefaultMetaDataStorage()
60      {
61          initFilters();
62      }
63  
64      private void initFilters()
65      {
66          List<String> metaDataStorageFilterClassNames = new ArrayList<String>();
67  
68          metaDataStorageFilterClassNames
69              .add(ExtValCoreConfiguration.get().customMetaDataStorageFilterClassName());
70          metaDataStorageFilterClassNames
71              .add(ExtValContext.getContext().getInformationProviderBean().get(
72                      CustomInformation.META_DATA_STORAGE_FILTER));
73  
74          MetaDataStorageFilter metaDataStorageFilter;
75          for (String validationExceptionInterceptorName : metaDataStorageFilterClassNames)
76          {
77              metaDataStorageFilter =
78                  (MetaDataStorageFilter)ClassUtils.tryToInstantiateClassForName(validationExceptionInterceptorName);
79  
80              if (metaDataStorageFilter != null)
81              {
82                  this.metaDataStorageFilters.add(metaDataStorageFilter);
83  
84                  logAddedFilter(metaDataStorageFilter.getClass());
85              }
86          }
87      }
88  
89      public void storeMetaDataOf(PropertyInformation propertyInformation)
90      {
91          invokeFilters(propertyInformation);
92  
93          PropertyInformation propertyInformationToStore = new DefaultPropertyInformation();
94  
95          PropertyDetails propertyDetails = propertyInformation
96                  .getInformation(PropertyInformationKeys.PROPERTY_DETAILS, PropertyDetails.class);
97  
98          copyMetaData(propertyInformation, propertyInformationToStore);
99  
100         getMapForClass(ProxyUtils.getUnproxiedClass(propertyDetails.getBaseObject().getClass()))
101                 .put(propertyDetails.getProperty(), propertyInformationToStore);
102     }
103 
104     private void invokeFilters(PropertyInformation propertyInformation)
105     {
106         for(MetaDataStorageFilter filter : this.metaDataStorageFilters)
107         {
108             filter.filter(propertyInformation);
109         }
110     }
111 
112     public MetaDataEntry[] getMetaData(Class targetClass, String targetProperty)
113     {
114         PropertyInformation propertyInformation = getMapForClass(targetClass).get(targetProperty);
115 
116         PropertyInformation clonedPropertyInformation = new DefaultPropertyInformation();
117         copyMetaData(propertyInformation, clonedPropertyInformation);
118 
119         return clonedPropertyInformation.getMetaDataEntries();
120     }
121 
122     public boolean containsMetaDataFor(Class targetClass, String targetProperty)
123     {
124         return getMapForClass(targetClass).containsKey(targetProperty);
125     }
126 
127     public void registerFilter(MetaDataStorageFilter storageFilter)
128     {
129         synchronized (this)
130         {
131             if(!isFilterDenied(storageFilter) && !isFilterAlreadyRegistered(storageFilter))
132             {
133                 this.metaDataStorageFilters.add(storageFilter);
134                 logAddedFilter(storageFilter.getClass());
135             }
136         }
137     }
138 
139     private boolean isFilterDenied(MetaDataStorageFilter storageFilter)
140     {
141         return this.deniedMetaDataFilters.contains(getStorageFilterClass(storageFilter));
142     }
143 
144     private boolean isFilterAlreadyRegistered(MetaDataStorageFilter storageFilter)
145     {
146         for(MetaDataStorageFilter filter : this.metaDataStorageFilters)
147         {
148             if(filter.getClass().equals(getStorageFilterClass(storageFilter)))
149             {
150                 return true;
151             }
152         }
153         return false;
154     }
155 
156     public void deregisterFilter(Class<? extends MetaDataStorageFilter> filterClass)
157     {
158         MetaDataStorageFilter storageFilter = ClassUtils.tryToInstantiateClass(filterClass);
159 
160         synchronized (this)
161         {
162             this.metaDataStorageFilters.remove(storageFilter);
163         }
164 
165         logRemovedFilter(storageFilter.getClass());
166     }
167 
168     public void denyFilter(Class<? extends MetaDataStorageFilter> filterClass)
169     {
170         synchronized (this)
171         {
172             for(Class<? extends MetaDataStorageFilter> filterId : this.deniedMetaDataFilters)
173             {
174                 if(filterId.equals(filterClass))
175                 {
176                     return;
177                 }
178             }
179             this.deniedMetaDataFilters.add(filterClass);
180         }
181 
182         deregisterFilter(filterClass);
183     }
184 
185     @ToDo(Priority.MEDIUM)
186     private void copyMetaData(PropertyInformation source, PropertyInformation target)
187     {
188         MetaDataEntry newMetaDataEntry;
189         for(MetaDataEntry metaDataEntry : source.getMetaDataEntries())
190         {
191             newMetaDataEntry = new MetaDataEntry();
192             newMetaDataEntry.setKey(metaDataEntry.getKey());
193             newMetaDataEntry.setValue(metaDataEntry.getValue());
194 
195             target.addMetaDataEntry(newMetaDataEntry);
196         }
197     }
198 
199     private void logAddedFilter(Class<? extends MetaDataStorageFilter> filterClass)
200     {
201         this.logger.info(filterClass.getName() + " added");
202     }
203 
204     private void logRemovedFilter(Class<? extends MetaDataStorageFilter> filterClass)
205     {
206         this.logger.info(filterClass.getName() + " removed");
207     }
208 
209     private Map<String, PropertyInformation> getMapForClass(Class target)
210     {
211         String key = ProxyUtils.getClassName(target);
212         if(!this.cachedPropertyInformation.containsKey(key))
213         {
214             this.cachedPropertyInformation.put(key,
215                 new NullValueAwareConcurrentHashMap<String, PropertyInformation>(new NullMarkerPropertyInformation()));
216         }
217         return this.cachedPropertyInformation.get(key);
218     }
219 
220     private static class NullMarkerPropertyInformation implements PropertyInformation
221     {
222         public boolean containsInformation(String key)
223         {
224             throw new UnsupportedOperationException();
225         }
226 
227         public Object getInformation(String key)
228         {
229             throw new UnsupportedOperationException();
230         }
231 
232         public <T> T getInformation(String key, Class<T> targetClass)
233         {
234             throw new UnsupportedOperationException();
235         }
236 
237         public void setInformation(String key, Object value)
238         {
239             throw new UnsupportedOperationException();
240         }
241 
242         public MetaDataEntry[] getMetaDataEntries()
243         {
244             throw new UnsupportedOperationException();
245         }
246 
247         public void addMetaDataEntry(MetaDataEntry metaDataEntry)
248         {
249             throw new UnsupportedOperationException();
250         }
251 
252         public void resetMetaDataEntries()
253         {
254             throw new UnsupportedOperationException();
255         }
256 
257         @Override
258         public int hashCode()
259         {
260             return getClass().hashCode();
261         }
262 
263         @Override
264         public boolean equals(Object target)
265         {
266             return target != null && getClass().equals(target.getClass());
267         }
268     }
269 
270     private Class<? extends MetaDataStorageFilter> getStorageFilterClass(MetaDataStorageFilter storageFilter)
271     {
272         return ProxyUtils.getUnproxiedClass(storageFilter.getClass(), MetaDataStorageFilter.class);
273     }
274 }