Java tutorial
/* * Copyright 2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package grails.plugin.searchable.internal; import grails.plugin.searchable.internal.util.PatternUtils; import java.beans.PropertyDescriptor; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler; import org.codehaus.groovy.grails.commons.GrailsApplication; import org.codehaus.groovy.grails.commons.GrailsClassUtils; import org.codehaus.groovy.grails.commons.GrailsDomainClass; import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty; import org.compass.core.Compass; import org.compass.core.mapping.Mapping; import org.compass.core.mapping.ResourceMapping; import org.compass.core.mapping.osem.ObjectMapping; import org.compass.core.spi.InternalCompass; import org.springframework.beans.BeanUtils; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.util.Assert; /** * General purpose utilities for the Grails Searchable Plugin * * @author Maurice Nicholson */ public class SearchableUtils { private static Log log = LogFactory.getLog(SearchableUtils.class); private static final String PROJECT_META_FILE = "application.properties"; public static final String SEARCHABLE_PROPERTY_NAME = "searchable"; public static final String ONLY = "only"; public static final String EXCEPT = "except"; /** * Is the given class an emebedded property of another domain class? * @param grailsDomainClass the GrailsDomainClass to check as n embedded property * @param grailsDomainClasses all GrailsDomainClasses * @return true if the given class is an embedded property of another class */ public static boolean isEmbeddedPropertyOfOtherDomainClass(GrailsDomainClass grailsDomainClass, Collection grailsDomainClasses) { for (Iterator iter = grailsDomainClasses.iterator(); iter.hasNext();) { GrailsDomainClass other = (GrailsDomainClass) iter.next(); if (grailsDomainClass == other) { continue; } GrailsDomainClassProperty[] domainClassProperties = other.getProperties(); for (int i = 0; i < domainClassProperties.length; i++) { GrailsDomainClass referencedDomainClass = domainClassProperties[i].getReferencedDomainClass(); if (referencedDomainClass != null && referencedDomainClass == grailsDomainClass && domainClassProperties[i].isEmbedded()) { return true; } } } return false; } /** * Get the given domain class's searchable property value, if any * * @param grailsDomainClass the Grails domain class * @return the searchable property value, or null */ public static Object getSearchablePropertyValue(GrailsDomainClass grailsDomainClass) { return GrailsClassUtils.getStaticPropertyValue(grailsDomainClass.getClazz(), SEARCHABLE_PROPERTY_NAME); } /** * Gets the GrailsDomainClass artefacts from the aplication * @param application the Grails app * @return the Lit of domain classes */ public static Collection getGrailsDomainClasses(GrailsApplication application) { Assert.notNull(application, "GrailsApplication cannot be null"); Set domainClasses = new HashSet(); for (int i = 0, max = application.getArtefacts(DomainClassArtefactHandler.TYPE).length; i < max; i++) { GrailsDomainClass grailsDomainClass = (GrailsDomainClass) application .getArtefacts(DomainClassArtefactHandler.TYPE)[i]; domainClasses.add(grailsDomainClass); } return domainClasses; } /** * Get the identifier of the given domain class instance * @param compass Compass * @param alias Compass alias * @param instance object instance * @return identifier */ public static Serializable getIdent(Compass compass, String alias, Object instance) { Assert.notNull(alias, "alias cannot be null"); ResourceMapping resourceMapping = ((InternalCompass) compass).getMapping().getMappingByAlias(alias); Mapping[] ids = resourceMapping.getIdMappings(); if (ids == null || ids.length == 0) { throw new IllegalArgumentException("Null or empty id mappings for alias [" + alias + "]"); } if (ids.length > 1) { throw new IllegalArgumentException("Too many id mappings for alias [" + alias + "]: expected only 1"); } return (Serializable) ((ObjectMapping) ids[0]).getGetter().get(instance); } /** * Returns the class type of the searchable property * @param grailsDomainClass * @param propertyName * @param searchableGrailsDomainClasses * @return */ public static Class getSearchablePropertyAssociatedClass(GrailsDomainClass grailsDomainClass, String propertyName, Collection searchableGrailsDomainClasses) { Assert.notNull(grailsDomainClass, "grailsDomainClass cannot be null"); Assert.notNull(propertyName, "propertyName cannot be null"); return getSearchablePropertyAssociatedClass(grailsDomainClass.getPropertyByName(propertyName), searchableGrailsDomainClasses); } /** * Returns the class type of the searchable property * @param property * @param searchableGrailsDomainClasses * @return */ public static Class getSearchablePropertyAssociatedClass(GrailsDomainClassProperty property, Collection searchableGrailsDomainClasses) { Assert.notNull(property, "property cannot be null"); Assert.notNull(property.getDomainClass(), "grailsDomainClass cannot be null"); Class propertyType = property.getType(); Collection classes = getClasses(searchableGrailsDomainClasses); if (classes.contains(propertyType)) { return propertyType; } propertyType = property.getDomainClass().getRelatedClassType(property.getName()); if (propertyType != null && classes.contains(propertyType)) { return propertyType; } // Handle generic collection types, e.g. Set<MyDomainClass>, for transient properties. propertyType = property.getType(); if (Collection.class.isAssignableFrom(propertyType)) { Class elementClass = getElementClass(property); if (classes.contains(elementClass)) return elementClass; } return null; } /** * If the given domain class property is a generic collection, this method * returns the element type of that collection. Otherwise, it returns * <code>null</code>. */ public static Class getElementClass(GrailsDomainClassProperty property) { PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(property.getDomainClass().getClazz(), property.getName()); Type type = descriptor.getReadMethod().getGenericReturnType(); if (type instanceof ParameterizedType) { for (Type argType : ((ParameterizedType) type).getActualTypeArguments()) { return (Class) argType; } } return null; } /** * Returns a collection of user classes for the given GrailsDomainClass instances * @param grailsDomainClasses a collection of GrailsDomainClass instances * @return a collection of user classes */ public static Collection getClasses(Collection grailsDomainClasses) { Assert.notNull(grailsDomainClasses, "grailsDomainClasses cannot be null"); Set classes = new HashSet(); for (Iterator iter = grailsDomainClasses.iterator(); iter.hasNext();) { classes.add(((GrailsDomainClass) iter.next()).getClazz()); } return classes; } /** * Should the named property be included in the mapping, according to the value of "searchable"? * @param propertyName * @param searchable * @return true if included */ public static boolean isIncludedProperty(String propertyName, Object searchable) { if (searchable == null || (searchable instanceof Boolean && ((Boolean) searchable))) { return true; } if (!(searchable instanceof Map)) { return false; } Object only = ((Map) searchable).get(ONLY); if (only != null) { return isOrContains(propertyName, only); } return !isOrContains(propertyName, ((Map) searchable).get(EXCEPT)); } private static boolean isOrContains(String thing, final Object value) { Collection values = null; if (value instanceof Collection) { values = (Collection) value; } else { values = new HashSet(); ((Set) values).add(value); } for (Iterator iter = values.iterator(); iter.hasNext();) { String v = (String) iter.next(); if (!PatternUtils.hasWildcards(v)) { if (v.equals(thing)) { return true; } } else { Pattern pattern = PatternUtils.makePatternFromWilcardString(v); if (pattern.matcher(thing).matches()) { return true; } } } return false; } /** * Tries to resolve the Grails application name * @param grailsApplication the GrailsApplication instance which may be null * @return the app name or "app.name" if not found */ public static String getAppName(GrailsApplication grailsApplication) { Map metadata = null; if (grailsApplication != null) { metadata = grailsApplication.getMetadata(); } if (metadata == null) { metadata = loadMetadata(); } if (metadata == null || !metadata.containsKey("app.name")) { return "app.name"; } return (String) metadata.get("app.name"); } // adapted from DefaultGrailsApplication private static Map loadMetadata() { Resource r = new ClassPathResource(PROJECT_META_FILE); if (r.exists()) { return loadMetadata(r); } String basedir = System.getProperty("base.dir"); if (basedir != null) { r = new FileSystemResource(new File(basedir, PROJECT_META_FILE)); if (r.exists()) { return loadMetadata(r); } } return null; } private static Map loadMetadata(Resource resource) { try { Properties meta = new Properties(); meta.load(resource.getInputStream()); return meta; } catch (IOException e) { // GrailsUtil.deepSanitize(e); log.warn("No application metadata file found at " + resource); } return null; } }