org/codehaus/griffon/runtime/core/AbstractArtifactManager.java

`AbstractArtifactManager.java`
`001 /* 002 * Copyright 2009-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.codehaus.griffon.runtime.core; 018 019 import griffon.core.*; 020 import griffon.util.CallableWithArgs; 021 import griffon.util.CallableWithArgsClosure; 022 import groovy.lang.*; 023 import org.slf4j.Logger; 024 import org.slf4j.LoggerFactory; 025 026 import java.util.*; 027 import java.util.regex.Matcher; 028 import java.util.regex.Pattern; 029 030 import static griffon.util.GriffonNameUtils.isBlank; 031 import static griffon.util.GriffonNameUtils.uncapitalize; 032 import static org.codehaus.groovy.runtime.DefaultGroovyMethods.toList; 033 034 /** 035 * Base implementation of the {@code ArtifactManager} interface. 036 * 037 * @author Andres Almiray 038 * @since 0.9.2 039 */ 040 public abstract class AbstractArtifactManager implements ArtifactManager { 041 private final GriffonApplication app; 042 043 private final Map<String, ArtifactInfo[]> artifacts = new LinkedHashMap<String, ArtifactInfo[]>(); 044 private final Map<String, ArtifactHandler> artifactHandlers = new LinkedHashMap<String, ArtifactHandler>(); 045 private final Object lock = new Object(); 046 047 private static final Logger LOG = LoggerFactory.getLogger(AbstractArtifactManager.class); 048 private static final Pattern GET_METHOD_PATTERN = Pattern.compile("^get(\\w+)Classes$"); 049 private static final Pattern IS_METHOD_PATTERN = Pattern.compile("^is(\\w+)Class$"); 050 private static final Pattern PROPERTY_PATTERN = Pattern.compile("^(\\w+)Classes$"); 051 052 public AbstractArtifactManager(GriffonApplication app) { 053 this.app = app; 054 } 055 056 public GriffonApplication getApp() { 057 return app; 058 } 059 060 protected Map<String, ArtifactInfo[]> getArtifacts() { 061 return artifacts; 062 } 063 064 protected Map<String, ArtifactHandler> getArtifactHandlers() { 065 return artifactHandlers; 066 } 067 068 public final void loadArtifactMetadata() { 069 Map<String, List<ArtifactInfo>> loadedArtifacts = doLoadArtifactMetadata(); 070 071 synchronized (lock) { 072 for (Map.Entry<String, List<ArtifactInfo>> artifactsEntry : loadedArtifacts.entrySet()) { 073 String type = artifactsEntry.getKey(); 074 List<ArtifactInfo> list = artifactsEntry.getValue(); 075 artifacts.put(type, list.toArray(new ArtifactInfo[list.size()])); 076 ArtifactHandler handler = artifactHandlers.get(type); 077 if (handler != null) handler.initialize(artifacts.get(type)); 078 } 079 } 080 } 081 082 // commented out generics because it fails with groovy 1.8.1 083 protected abstract Map<String, List<ArtifactInfo>> doLoadArtifactMetadata(); 084 085 public void registerArtifactHandler(ArtifactHandler handler) { 086 if (handler == null) return; 087 if (LOG.isInfoEnabled()) { 088 LOG.info("Registering artifact handler for type '" + handler.getType() + "': " + handler); 089 } 090 synchronized (lock) { 091 artifactHandlers.put(handler.getType(), handler); 092 if (artifacts.get(handler.getType()) != null) handler.initialize(artifacts.get(handler.getType())); 093 } 094 } 095 096 public void unregisterArtifactHandler(ArtifactHandler handler) { 097 if (handler == null) return; 098 if (LOG.isInfoEnabled()) { 099 LOG.info("Removing artifact handler for type '" + handler.getType() + "': " + handler); 100 } 101 synchronized (lock) { 102 artifactHandlers.remove(handler.getType()); 103 } 104 } 105 106 public GriffonClass findGriffonClass(String name, String type) { 107 if (isBlank(name) || isBlank(type)) return null; 108 if (LOG.isDebugEnabled()) { 109 LOG.debug("Searching for griffonClass of " + type + ":" + name); 110 } 111 synchronized (lock) { 112 ArtifactHandler handler = artifactHandlers.get(type); 113 return handler != null ? handler.findClassFor(name) : null; 114 } 115 } 116 117 public GriffonClass findGriffonClass(Class clazz, String type) { 118 if (LOG.isDebugEnabled()) { 119 LOG.debug("Searching for griffonClass of " + type + ":" + clazz.getName()); 120 } 121 synchronized (lock) { 122 ArtifactHandler handler = artifactHandlers.get(type); 123 return handler != null ? handler.getClassFor(clazz) : null; 124 } 125 } 126 127 public GriffonClass findGriffonClass(Object obj) { 128 if (obj == null) return null; 129 if (LOG.isDebugEnabled()) { 130 LOG.debug("Searching for griffonClass of " + obj); 131 } 132 synchronized (lock) { 133 return findGriffonClass(obj.getClass()); 134 } 135 } 136 137 public GriffonClass findGriffonClass(Class clazz) { 138 if (clazz == null) return null; 139 if (LOG.isDebugEnabled()) { 140 LOG.debug("Searching for griffonClass of " + clazz.getName()); 141 } 142 synchronized (lock) { 143 for (ArtifactHandler handler : artifactHandlers.values()) { 144 GriffonClass griffonClass = handler.getClassFor(clazz); 145 if (griffonClass != null) return griffonClass; 146 } 147 } 148 return null; 149 } 150 151 public GriffonClass findGriffonClass(String fqnClassName) { 152 if (isBlank(fqnClassName)) return null; 153 if (LOG.isDebugEnabled()) { 154 LOG.debug("Searching for griffonClass of " + fqnClassName); 155 } 156 synchronized (lock) { 157 for (ArtifactHandler handler : artifactHandlers.values()) { 158 GriffonClass griffonClass = handler.getClassFor(fqnClassName); 159 if (griffonClass != null) return griffonClass; 160 } 161 } 162 return null; 163 } 164 165 public List<GriffonClass> getClassesOfType(String type) { 166 synchronized (lock) { 167 if (artifacts.containsKey(type)) { 168 return toList(artifactHandlers.get(type).getClasses()); 169 } 170 } 171 return EMPTY_GRIFFON_CLASS_LIST; 172 } 173 174 public List<GriffonClass> getAllClasses() { 175 List<GriffonClass> all = new ArrayList<GriffonClass>(); 176 synchronized (lock) { 177 for (ArtifactHandler handler : artifactHandlers.values()) { 178 all.addAll(toList(handler.getClasses())); 179 } 180 } 181 return Collections.unmodifiableList(all); 182 } 183 184 /** 185 * Adds dynamic handlers for querying artifact classes.<p> 186 * The following patterns are recognized<ul> 187 * <li>getXXXClasses</li> 188 * <li>isXXXClass</li> 189 * </ul> 190 * where {@code XXX} stands for the name of an artifact, like 191 * "Controller" or "Service". 192 */ 193 public Object methodMissing(final String methodName, Object args) { 194 Object[] arguments = new Object[0]; 195 if (args != null && args.getClass().isArray()) { 196 arguments = (Object[]) args; 197 } else { 198 arguments = new Object[]{args}; 199 } 200 201 Matcher matcher = GET_METHOD_PATTERN.matcher(methodName); 202 if (matcher.matches()) { 203 final String artifactType = uncapitalize(matcher.group(1)); 204 if (arguments.length == 0 && artifacts.containsKey(artifactType)) { 205 MetaClass mc = GroovySystem.getMetaClassRegistry().getMetaClass(ArtifactManager.class); 206 if (mc instanceof ExpandoMetaClass) { 207 ExpandoMetaClass emc = (ExpandoMetaClass) mc; 208 CallableWithArgs<List<GriffonClass>> callable = new CallableWithArgs<List<GriffonClass>>() { 209 public List<GriffonClass> call(Object[] params) { 210 if (params != null) { 211 throw new MissingMethodException(methodName, ArtifactManager.class, params); 212 } 213 return getClassesOfType(artifactType); 214 } 215 }; 216 emc.registerInstanceMethod(methodName, new CallableWithArgsClosure(this, callable)); 217 } 218 return getClassesOfType(artifactType); 219 } 220 return EMPTY_GRIFFON_CLASS_ARRAY; 221 } 222 223 matcher = IS_METHOD_PATTERN.matcher(methodName); 224 if (matcher.matches()) { 225 final String artifactType = uncapitalize(matcher.group(1)); 226 if (arguments.length == 1 && artifacts.containsKey(artifactType)) { 227 MetaClass mc = GroovySystem.getMetaClassRegistry().getMetaClass(ArtifactManager.class); 228 if (mc instanceof ExpandoMetaClass) { 229 ExpandoMetaClass emc = (ExpandoMetaClass) mc; 230 CallableWithArgs<Boolean> callable = new CallableWithArgs<Boolean>() { 231 public Boolean call(Object[] params) { 232 if (params == null || params.length != 1 || !(params[0] instanceof Class)) { 233 throw new MissingMethodException(methodName, ArtifactManager.class, params); 234 } 235 Class klass = (Class) params[0]; 236 return isClassOfType(artifactType, klass); 237 } 238 }; 239 emc.registerInstanceMethod(methodName, new CallableWithArgsClosure(this, callable)); 240 } 241 return isClassOfType(artifactType, (Class) arguments[0]); 242 } 243 return false; 244 } 245 246 throw new MissingMethodException(methodName, ArtifactManager.class, arguments); 247 } 248 249 /** 250 * Adds dynamic handlers for querying artifact classes.<p> 251 * The following patterns are recognized<ul> 252 * <li>xXXClasses</li> 253 * </ul> 254 * where {@code xXX} stands for the name of an artifact, like 255 * "controller" or "service". 256 */ 257 public Object propertyMissing(String propertyName) { 258 Matcher matcher = PROPERTY_PATTERN.matcher(propertyName); 259 if (matcher.matches()) { 260 final String artifactType = uncapitalize(matcher.group(1)); 261 if (artifacts.containsKey(artifactType)) { 262 List<GriffonClass> griffonClasses = getClassesOfType(artifactType); 263 MetaClass mc = GroovySystem.getMetaClassRegistry().getMetaClass(ArtifactManager.class); 264 if (mc instanceof ExpandoMetaClass) { 265 ExpandoMetaClass emc = (ExpandoMetaClass) mc; 266 emc.registerBeanProperty(propertyName, griffonClasses); 267 } 268 return griffonClasses; 269 } 270 return EMPTY_GRIFFON_CLASS_ARRAY; 271 } 272 273 throw new MissingPropertyException(propertyName, Object.class); 274 } 275 276 protected boolean isClassOfType(String type, Class clazz) { 277 for (ArtifactInfo artifactInfo : artifacts.get(type)) { 278 if (artifactInfo.getClazz().getName().equals(clazz.getName())) { 279 return true; 280 } 281 } 282 return false; 283 } 284 }`