001: /*
002: * Copyright 2006-2007 Luca Garulli (luca.garulli@assetdata.it)
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.romaframework.core.schema;
018:
019: import java.io.File;
020: import java.net.MalformedURLException;
021: import java.net.URL;
022: import java.util.ArrayList;
023: import java.util.HashMap;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030: import org.romaframework.core.Utility;
031: import org.romaframework.core.classloader.RomaClassLoader;
032: import org.romaframework.core.flow.Controller;
033: import org.romaframework.core.flow.ObjectContext;
034: import org.romaframework.core.resource.ResourceResolver;
035: import org.romaframework.core.resource.ResourceResolverListener;
036:
037: /**
038: * Resolve entity class and descriptors using the paths configured.
039: *
040: * @author Luca Garulli (luca.garulli@assetdata.it)
041: */
042: public class SchemaClassResolver implements ResourceResolverListener {
043:
044: private final Map<String, String> classes = new HashMap<String, String>();
045: private final Map<String, String> descriptors = new HashMap<String, String>();
046: private final Map<String, File> resourceFileOwnerMapping = new HashMap<String, File>();
047:
048: private List<String> packages = new ArrayList<String>();
049: private ResourceResolver resourceResolver;
050:
051: public static final String DOMAIN_PACKAGE_NAME = "domain";
052: public static final String CLASS_SUFFIX = ".class";
053: public static final String DESCRIPTOR_SUFFIX = ".xml";
054:
055: private static Log log = LogFactory
056: .getLog(SchemaClassResolver.class);
057:
058: public SchemaClassResolver(ResourceResolver iResourceResolver) {
059: resourceResolver = iResourceResolver;
060: Controller.getInstance().registerListener(
061: ResourceResolverListener.class, this );
062: }
063:
064: protected boolean acceptResorce(String iResource) {
065: return iResource.endsWith(CLASS_SUFFIX)
066: || iResource.endsWith(DESCRIPTOR_SUFFIX);
067: }
068:
069: public void addPackage(String iPath) {
070: log.debug("[SchemaClassResolver.addPackage] " + iPath);
071:
072: packages.add(iPath.replace(File.separatorChar, '.'));
073: resourceResolver.loadResources(iPath);
074: }
075:
076: public void setPackages(List<String> iPackages) {
077: for (String i : iPackages) {
078: addPackage(i);
079: }
080: }
081:
082: /**
083: * Get the Class instance for a requested entity.
084: *
085: * @param iEntityName
086: * Entity name to find
087: * @return Class instance if found, null otherwise
088: */
089: public Class<?> getEntityClass(String iEntityName) {
090: try {
091: String pkg = classes.get(iEntityName);
092: if (pkg == null)
093: return null;
094:
095: return Class.forName(pkg + iEntityName);
096: } catch (Throwable t) {
097: // NOT FOUND, TRY AGAIN WITH THE NEXT ONE
098: }
099: return null;
100: }
101:
102: /**
103: * Get the Class instance for a requested entity.
104: *
105: * @param iEntityName
106: * Entity name to find
107: * @return Class instance if found, null otherwise
108: */
109: public List<Class<?>> getEntityClassByInheritance(
110: Class<?> iBaseClass) {
111: List<Class<?>> result = new ArrayList<Class<?>>();
112:
113: Set<String> classNames = classes.keySet();
114:
115: for (String className : classNames) {
116: try {
117: String pkg = classes.get(className);
118: if (pkg == null)
119: continue;
120: Class<?> class1 = Class.forName(pkg + className);
121: if (iBaseClass.isAssignableFrom(class1))
122: result.add(class1);
123: } catch (Throwable t) {
124: // NOT FOUND, TRY AGAIN WITH THE NEXT ONE
125: }
126: }
127: return result;
128: }
129:
130: public List<Class<?>> getEntityClassesByPackage(String packageName) {
131: List<Class<?>> result = new ArrayList<Class<?>>();
132: if (classes == null)
133: return result;
134:
135: Set<String> classNames = classes.keySet();
136:
137: for (String className : classNames) {
138: try {
139: String pkg = classes.get(className);
140: if (pkg == null)
141: continue;
142: if (pkg.startsWith(packageName)) {
143: Class<?> class1 = Class.forName(pkg + className);
144: result.add(class1);
145: }
146: } catch (Exception e) {
147: }
148: }
149: return result;
150: }
151:
152: public String getEntityDescriptor(String iEntityName) {
153: String path = descriptors.get(iEntityName);
154: if (path == null)
155: return null;
156: return path + iEntityName + DESCRIPTOR_SUFFIX;
157: }
158:
159: public String[] getClassPackages() {
160: return packages.toArray(new String[packages.size()]);
161: }
162:
163: public void addDomainPackage(String iPath) {
164: addPackage(iPath + Utility.PACKAGE_SEPARATOR
165: + DOMAIN_PACKAGE_NAME);
166: }
167:
168: public void addResource(File iFile, String iName,
169: String iPackagePrefix, String iStartingPackage) {
170: if (!iPackagePrefix.startsWith(iStartingPackage))
171: return;
172:
173: if (iName.toLowerCase().endsWith(CLASS_SUFFIX)) {
174: addResourceClass(iFile, iName, iPackagePrefix);
175: } else if (iName.toLowerCase().endsWith(DESCRIPTOR_SUFFIX)) {
176: addResourceDescriptor(iFile, iName, iPackagePrefix);
177: }
178:
179: resourceFileOwnerMapping.put(iName, iFile);
180: }
181:
182: public File getFileOwner(String iResourceName) {
183: return resourceFileOwnerMapping.get(iResourceName);
184: }
185:
186: public Class<?> reloadEntityClass(String iClassName)
187: throws ClassNotFoundException {
188: String classPaths[] = ObjectContext.getInstance().getComponent(
189: ResourceResolver.class).getClassPaths();
190: URL[] urls = new URL[classPaths.length];
191: for (int i = 0; i < classPaths.length; ++i) {
192: for (String item : classPaths[i].split(File.pathSeparator)) {
193: try {
194: urls[i] = new File(item).toURL();
195: } catch (MalformedURLException e) {
196: log
197: .error("[RomaClassLoader.init] Bad url setting classpath: "
198: + item);
199: }
200: }
201: }
202:
203: RomaClassLoader clsLoader = new RomaClassLoader();
204: Thread.currentThread().setContextClassLoader(clsLoader);
205: Class<?> cls = clsLoader.reloadClass(iClassName);
206:
207: return cls;
208: }
209:
210: private void addResourceClass(File iFile, String iName,
211: String iPackagePrefix) {
212: // ADD A NEW CLASS
213: String name = iName.substring(0, iName.length()
214: - CLASS_SUFFIX.length());
215: String currentPath = classes.get(name);
216: if (currentPath != null) {
217: // ALREADY EXISTS
218: if (currentPath.equals(iPackagePrefix))
219: // SAME PATH: PROBABLY DUPLICATE JAR OR JAR+CLASSES REDOUNDANCY
220: log
221: .warn("[SchemaClassResolver.addResourceClass] Warning: found the class "
222: + name
223: + " defined twice in the classpath and they point to the same package "
224: + iPackagePrefix
225: + " Assure you have only one class to avoid alignment problems. Current path is: "
226: + iFile);
227: else
228: // ALREADY EXISTS
229: log
230: .warn("[SchemaClassResolver.addResourceClass] Found the class "
231: + name
232: + " defined twice. Ignore current package "
233: + iPackagePrefix
234: + " Use the first one found: "
235: + currentPath + " from path: " + iFile);
236: } else {
237: if (log.isDebugEnabled())
238: log
239: .debug("[SchemaClassResolver.addResourceClass] > Loading class: "
240: + iName
241: + " from path: "
242: + iFile
243: + " using the package: "
244: + iPackagePrefix);
245:
246: classes.put(name, iPackagePrefix);
247: }
248: }
249:
250: private void addResourceDescriptor(File iFile, String iName,
251: String iPackagePrefix) {
252: if (log.isDebugEnabled())
253: log
254: .debug("[SchemaClassResolver.addResourceDescriptor] > Loading descriptor: "
255: + iName + " from: " + iPackagePrefix);
256:
257: String currentPath = descriptors.get(iName);
258: String name = iName.substring(0, iName.length()
259: - DESCRIPTOR_SUFFIX.length());
260:
261: if (currentPath != null) {
262: // ALREADY EXISTS
263: if (currentPath.equals(iPackagePrefix))
264: // ALREADY EXISTS
265: log
266: .warn("[SchemaClassResolver.addResourceDescriptor] Warning: found the Xml Annotation "
267: + name
268: + " defined twice in the classpath and they point to the same package "
269: + iPackagePrefix
270: + " Assure you have only one class to avoid alignment problems. Current path is: "
271: + iFile);
272: else
273: // ALREADY EXISTS
274: log
275: .warn("[SchemaClassResolver.addResourceDescriptor] Found the Xml Annotation "
276: + name
277: + " defined twice. Ignore current package "
278: + iPackagePrefix
279: + " Use the first one found: "
280: + currentPath + " from path: " + iFile);
281: } else {
282: if (log.isDebugEnabled())
283: log
284: .debug("[SchemaClassResolver.addResourceDescriptor] > Loading Xml Annotation: "
285: + iName
286: + " from path: "
287: + iFile
288: + " using the package: "
289: + iPackagePrefix);
290:
291: descriptors.put(name, Utility.PATH_SEPARATOR
292: + iPackagePrefix.replace('.',
293: Utility.PATH_SEPARATOR));
294: }
295: }
296: }
|