View Javadoc
1   /**
2    * Copyright 2014 Internet2
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  /*
17    Copyright (C) 2004-2007 University Corporation for Advanced Internet Development, Inc.
18    Copyright (C) 2004-2007 The University Of Chicago
19  
20    Licensed under the Apache License, Version 2.0 (the "License");
21    you may not use this file except in compliance with the License.
22    You may obtain a copy of the License at
23  
24      http://www.apache.org/licenses/LICENSE-2.0
25  
26    Unless required by applicable law or agreed to in writing, software
27    distributed under the License is distributed on an "AS IS" BASIS,
28    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29    See the License for the specific language governing permissions and
30    limitations under the License.
31  */
32  
33  package edu.internet2.middleware.grouper;
34  import java.util.Iterator;
35  import java.util.LinkedHashMap;
36  import java.util.LinkedHashSet;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.Set;
40  
41  import org.apache.commons.lang.StringUtils;
42  import org.apache.commons.logging.Log;
43  
44  import edu.internet2.middleware.grouper.cache.GrouperCache;
45  import edu.internet2.middleware.grouper.exception.GrouperException;
46  import edu.internet2.middleware.grouper.exception.SchemaException;
47  import edu.internet2.middleware.grouper.internal.dao.GrouperDAOException;
48  import edu.internet2.middleware.grouper.misc.GrouperDAOFactory;
49  import edu.internet2.middleware.grouper.misc.GrouperStartup;
50  import edu.internet2.middleware.grouper.privs.Privilege;
51  import edu.internet2.middleware.grouper.util.GrouperUtil;
52  
53  
54  /**
55   * Find fields.
56   * <p/>
57   * @author  blair christensen.
58   * @version $Id: FieldFinder.java,v 1.48 2009-08-11 20:18:08 mchyzer Exp $
59   */
60  public class FieldFinder {
61  
62    /** cache name */
63    static String cacheName = FieldFinder.class.getName() + ".fieldCache";
64  
65    /**
66     * logger 
67     */
68    private static final Log LOG = GrouperUtil.getLog(FieldFinder.class);
69  
70    /** default field cache seconds */
71    static int defaultFieldCacheSeconds = 1*600;
72    
73    /** last time refreshed, for testing */
74    static long lastTimeRefreshed = -1;
75    
76    /** 
77     * every X minutes, get new elements.  access this with fieldCache() so it is not null
78     * store this as a complete map in the cache so that elements dont disappear
79     */
80    static GrouperCache<Boolean, Map<String,Field>> fieldGrouperCache;
81  
82    /**
83     * <pre>
84     * return the field cache.
85     * 
86     * Customize with:
87     *   &lt;cache  name="edu.internet2.middleware.grouper.FieldFinder.fieldCache"
88     *        maxElementsInMemory="10000"
89     *        eternal="false"
90     *        timeToIdleSeconds="86400"
91     *        timeToLiveSeconds="86400"
92     *        overflowToDisk="false"
93     * /&gt;
94     * 
95     * </pre>
96     * @return cache
97     */
98    public static GrouperCache<Boolean, Map<String,Field>> fieldGrouperCache() {
99      if (fieldGrouperCache == null) {
100       fieldGrouperCache = new GrouperCache<Boolean, Map<String,Field>>(
101           cacheName, 10000, false, 
102           defaultFieldCacheSeconds, defaultFieldCacheSeconds, false);
103       fieldGrouperCache.registerDatabaseClearableCache();
104     }
105     return fieldGrouperCache;
106   }
107   
108   /**
109    * init and return the cache
110    * @return the cache
111    */
112   private static Map<String,Field> fieldCache() {
113     GrouperCache<Boolean, Map<String, Field>> theFieldOuterGrouperCache = fieldGrouperCache();
114     Map<String,Field> theFieldCache = theFieldOuterGrouperCache.get(Boolean.TRUE);
115     if (theFieldCache == null || theFieldCache.size() == 0) {
116       
117       // dont synchronize, just sleep a bit to reduce deadlock
118       GrouperUtil.sleep(Math.round(Math.random() * 100d));
119       theFieldCache = theFieldOuterGrouperCache.get(Boolean.TRUE);
120       
121       if (theFieldCache == null || theFieldCache.size() == 0) {
122         theFieldCache = internal_updateKnownFields();
123       }
124     }
125     return theFieldCache;
126   }
127 
128   /**
129    * @param name
130    * @param type
131    * @return the field id
132    */
133   @Deprecated
134   public static String findFieldId(String name, String type) {
135     return findFieldId(name, type, true);
136   }
137 
138   /**
139    * @param name
140    * @param type
141    * @param exceptionIfNull
142    * @return the field id
143    */
144   public static String findFieldId(String name, String type, boolean exceptionIfNull) {
145 
146     //if both null then we are all set
147     if (StringUtils.isBlank(name) && StringUtils.isBlank(type)) {
148       return null;
149     }
150 
151     //either both blank, or both filled in
152     if (StringUtils.isBlank(name) || StringUtils.isBlank(type)) {
153       throw new RuntimeException("Name or type cannot be blank: '" + name + "', '" + type + "'");
154     }
155     
156     Field field = FieldFinder.find(name, false);
157     if (field != null) {
158       if (!StringUtils.equals(field.getTypeString(), type)) {
159         throw new RuntimeException("Field with name '" + name + "' should have type: '" + type 
160             + "' but instead has type: '" + field.getTypeString() + "'");
161       }
162       return field.getUuid();
163     }
164     if (exceptionIfNull) {
165       throw new RuntimeException("Problem finding attribute name: " + name);
166     }
167     return null;
168   }
169 
170   /**
171    * find all ids by type
172    * @param type
173    * @return all ids by type
174    */
175   public static List<String> findAllIdsByType(FieldType type) {
176     try {
177       Set<Field> fields = findAllByType(type);
178       List<String> fieldIds = GrouperUtil.propertyList(fields, Field.PROPERTY_UUID, String.class);
179       return fieldIds;
180     } catch (SchemaException se) {
181       throw new RuntimeException("Problem finding fields by type: " + type, se);
182     }
183   }
184 
185   /**
186    * Get the specified field.
187    * <pre class="eg">
188    * Field f = FieldFinder.find(field);
189    * </pre>
190    * @param   name  Name of {@link Field} to return.
191    * @return field
192    * @throws  SchemaException
193    */
194   @Deprecated
195   public static Field find(String name) throws  SchemaException {
196     return find(name, true);
197   }
198 
199   /**
200    * Get the specified field.
201    * <pre class="eg">
202    * Field f = FieldFinder.find(field);
203    * </pre>
204    * @param   name  Name of {@link Field} to return.
205    * @param exceptionIfNotFound true if exception if not found, otherwise null
206    * @return field
207    * @throws  SchemaException
208    */
209   public static Field find(String name, boolean exceptionIfNotFound) {
210     return find(name, exceptionIfNotFound, true);
211   }
212 
213   /**
214    * Get the specified field.
215    * <pre class="eg">
216    * Field f = FieldFinder.find(field);
217    * </pre>
218    * @param   name  Name of {@link Field} to return.
219    * @param exceptionIfNotFound true if exception if not found, otherwise null
220    * @param includePrivilegeSearch if should also use name as privilege
221    * @return field
222    * @throws  SchemaException
223    */
224   public static Field find(String name, boolean exceptionIfNotFound, boolean includePrivilegeSearch) 
225     throws  SchemaException {
226     Map<String, Field> theFieldCache = fieldCache();
227     if ( theFieldCache.containsKey(name) ) {
228       return theFieldCache.get(name);
229     }
230     
231     //try by privilege name
232     if (includePrivilegeSearch) {
233       try {
234         Privilege privilege = Privilege.getInstance(name);
235         if (privilege != null ) {
236           Field field = privilege.getField();
237           if (field != null) {
238             return field;
239           }
240         }
241       } catch (Exception e) {
242         //this is generally ok
243         if (LOG.isDebugEnabled()) {
244           LOG.debug("Problem finding privilege: " + name, e);
245         }
246       }
247     }
248     if (exceptionIfNotFound) {
249       //dont refresh more than 2 minutes (or whatever it is set for)
250       throw new SchemaException("field not found: " + name + ", expecting one of: "
251         + GrouperUtil.stringValue(fieldCache().keySet()));
252     }
253     return null;
254   } 
255 
256   /**
257    * Get the specified field by id.
258    * @param   fieldId  fieldId
259    * @return the field or null if fieldId is blank.  will throw runtime exception if the field is not found
260    * @deprecated use the overload
261    */
262   @Deprecated
263   public static Field findById(String fieldId) {
264     return findById(fieldId, true);
265   }
266 
267   /**
268    * Get the specified field by id.
269    * @param   fieldId  fieldId
270    * @param exceptionIfNull
271    * @return the field or null if fieldId is blank.  will throw runtime exception if the field is not found
272    */
273   public static Field findById(String fieldId, boolean exceptionIfNull) {
274     if (StringUtils.isBlank(fieldId)) {
275       return null;
276     }
277     Map<String, Field> theFieldCache = fieldCache();
278 
279     for (Field field : theFieldCache.values()) {
280       if (StringUtils.equals(fieldId, field.getUuid())) {
281         return field;
282       }
283     }
284     //update cache if not found
285     internal_updateKnownFields();
286     for (Field field : theFieldCache.values()) {
287       if (StringUtils.equals(fieldId, field.getUuid())) {
288         return field;
289       }
290     }
291     if (exceptionIfNull) {
292       throw new RuntimeException("Cant find field with id: '" + fieldId + "'");
293     }
294     return null;
295   } 
296 
297   /**
298    * Find all fields.
299    * <pre class="eg">
300    * Set fields = FieldFinder.findAll();
301    * </pre>
302    * @return  {@link Set} of {@link Field} objects.
303    * @throws  GrouperException
304    */
305   public static Set findAll() 
306     throws  GrouperException
307   {
308     Set<Field> fields  = new LinkedHashSet(fieldCache().values());
309     return fields;
310   }
311   
312     /**
313    * 
314    * @return all fields
315    * @throws GrouperException
316    */
317   private static Set findAllFromDb() throws GrouperException {
318     Set fields = new LinkedHashSet();
319     Iterator it = GrouperDAOFactory.getFactory().getField().findAll()
320         .iterator();
321     while (it.hasNext()) {
322       fields.add((Field) it.next());
323     }
324     return fields;
325   }
326   
327   /** 
328    * @param groupType 
329    * @return set of fields
330    * @throws GrouperDAOException 
331    */
332   public static Set<Field> findAllByGroupType(GroupType groupType)
333       throws  GrouperDAOException {
334     Set<Field> fields  = new LinkedHashSet();
335     
336     Set<Field> allListFields = FieldFinder.findAllByType(FieldType.LIST);
337     for (Field listField : allListFields) {
338       if (!listField.getUuid().equals(Group.getDefaultList().getUuid())) {
339         GroupType currGroupType = GroupTypeFinder.internal_findGroupTypeByField(listField, false);
340         if (currGroupType != null && groupType.getUuid().equals(currGroupType.getUuid())) {
341           fields.add(listField);
342         }
343       }
344     }
345 
346     return fields;
347   }
348   
349   /** 
350    * @param groupTypeId
351    * @return set of fields
352    * @throws GrouperDAOException 
353    */
354   public static Set<Field> findAllByGroupType(String groupTypeId)
355       throws  GrouperDAOException {
356     
357     @SuppressWarnings("deprecation")
358     GroupType groupType = GroupTypeFinder.findByUuid(groupTypeId, true);
359 
360     return findAllByGroupType(groupType);
361   }
362 
363   /**
364    * Find all fields of the specified type.
365    * <pre class="eg">
366    * Set types = FieldFinder.findAllByType(type);
367    * </pre>
368    * @param type 
369    * @return set of fields
370    * @throws SchemaException 
371    */
372   public static Set<Field> findAllByType(FieldType type) 
373     throws  SchemaException {
374     
375     Set<Field> fields  = new LinkedHashSet();
376     
377     for (Field field : fieldCache().values()) {
378       if (StringUtils.equals(type.getType(),field.getTypeString())) {
379         fields.add(field);
380       }
381     }
382     return fields;
383   }
384 
385   /**
386    * synchronize on this object
387    */
388   private static Object internal_updateKnownFieldsSemaphore = new Object();
389 
390   /**
391    * @return map
392    */
393   public static Map<String, Field> internal_updateKnownFields() {
394 
395     GrouperStartup.startup();
396     Map<String, Field> theFieldCache = new LinkedHashMap<String, Field>();
397 
398     Field f;
399     Set   fieldsInRegistry = findAllFromDb();
400     
401     // find fields to add to the cache
402     Iterator it = fieldsInRegistry.iterator();
403     while (it.hasNext()) {
404       f = (Field) it.next();
405       theFieldCache.put( f.getName(), f );
406       }
407 
408     fieldGrouperCache().put(Boolean.TRUE, theFieldCache);
409 
410     FieldFinder.lastTimeRefreshed = System.currentTimeMillis();
411     
412     return theFieldCache;
413   } 
414 
415   /**
416    * clear cache (e.g. if schema export)
417    */
418   public static void clearCache() {
419 
420     //if not there dont worry
421     if (fieldGrouperCache == null || fieldGrouperCache.get(Boolean.TRUE) == null ||
422         fieldGrouperCache.get(Boolean.TRUE).size() == 0) {
423       return;
424     }
425 
426     fieldGrouperCache().get(Boolean.TRUE).clear();
427   }
428   
429   /**
430    * 
431    * @param args
432    * @throws Exception 
433    */
434   public static void main(String[] args) throws Exception {
435     System.out.println(FieldFinder.find("update"));
436   }
437   
438 }
439