001: package org.vraptor.config;
002:
003: import java.io.File;
004: import java.io.IOException;
005: import java.io.InputStream;
006: import java.io.InputStreamReader;
007: import java.util.Set;
008:
009: import org.apache.log4j.Logger;
010: import org.vraptor.VRaptorServlet;
011: import org.vraptor.annotations.Component;
012: import org.vraptor.component.ComponentManager;
013: import org.vraptor.component.InvalidComponentException;
014: import org.vraptor.scope.ApplicationContext;
015: import org.vraptor.webapp.WebApplication;
016:
017: /**
018: * Base class for vraptor configuration.
019: *
020: * @author Guilherme Silveira
021: */
022: public class Configuration {
023:
024: private static final String VRAPTOR_XML_LOCATION = "/";
025:
026: private static final String WEBINF_CLASSES_DIRECTORY = "/WEB-INF/classes/";
027:
028: private static final Logger LOG = Logger
029: .getLogger(Configuration.class);
030:
031: private static final String DOT_CLASS = ".class";
032:
033: private final ApplicationContext context;
034:
035: private final ComponentManager componentManager;
036:
037: /**
038: * Checks if className is a valid Component (annotated)
039: *
040: * @param className
041: * @return
042: * @throws IllegalArgumentException
043: * if className cannot be loaded
044: */
045: private boolean classIsComponent(String className) {
046: try {
047: if (LOG.isDebugEnabled()) {
048: LOG.debug("Will check class " + className);
049: }
050: Class<?> type = Class.forName(className, false, this
051: .getClass().getClassLoader());
052: return type.isAnnotationPresent(Component.class);
053: } catch (ClassNotFoundException e) {
054: throw new IllegalArgumentException(String.format(
055: "cant check if %s is a class, unable to load it: "
056: + e, className), e);
057: }
058: }
059:
060: /**
061: * Parses a String like
062: * <code>/WEB-INF/classes/br/com/caelum/Test.class to</code>
063: * <code>br.com.caelum.Test.class</code>
064: *
065: * @param directory
066: * @param name
067: * @return
068: */
069: String parseClassName(String directory, String name) {
070: if (!name.startsWith(directory)) {
071: throw new IllegalArgumentException();
072: }
073: name = name.substring(directory.length(), name.length()
074: - DOT_CLASS.length());
075: name = name.replaceAll("/|\\\\", ".");
076: // bug fix for cargo
077: name = name.replaceAll("\\.\\.", ".");
078: return name;
079: }
080:
081: public Configuration(ApplicationContext applicationContext,
082: ComponentManager componentManager) {
083: this .context = applicationContext;
084: this .componentManager = componentManager;
085: }
086:
087: private void readDirectory() throws ConfigException {
088: LOG.info("loading components from WEB-INF/classes");
089: try {
090: readDirectory(WEBINF_CLASSES_DIRECTORY);
091: } catch (InvalidComponentException e) {
092: throw new ConfigException("cannot load classes", e);
093: }
094: }
095:
096: /**
097: * Reads all .class files from <code>directory</code> looking for
098: * annotated vraptor classes (@Component).
099: *
100: * @param directory
101: * @throws InvalidComponentException
102: */
103: private void readDirectory(String directory)
104: throws InvalidComponentException {
105: // TODO better code? shale does something similar
106: // TODO check jetty compatibility
107: @SuppressWarnings("unchecked")
108: Set<String> items = context.getResourcePaths(directory);
109:
110: if (items == null) {
111: LOG.info(directory + " not found");
112: return;
113: }
114:
115: for (String item : items) {
116: File file = new File(context.getRealPath(item));
117: if (file.isDirectory()) {
118: readDirectory(item);
119: } else if (item.endsWith(DOT_CLASS)) {
120: String className = parseClassName(
121: WEBINF_CLASSES_DIRECTORY, item);
122: if (classIsComponent(className)) {
123: if (LOG.isInfoEnabled()) {
124: LOG.info(String.format(
125: "component found %s: %s", directory,
126: className));
127: }
128: this .componentManager.register(className);
129: }
130: }
131: }
132: }
133:
134: public void load(WebApplication web) throws ConfigException {
135: boolean autoDiscover = true;
136: autoDiscover &= loadXml(web, "");
137: autoDiscover &= loadXml(web, "-vatx");
138: if (autoDiscover) {
139: autoDiscoverComponents();
140: }
141: }
142:
143: private boolean loadXml(WebApplication web, String suffix)
144: throws ConfigException {
145: InputStream file = getXMLFile(suffix);
146: if (file == null) {
147: LOG.info("No (optional) vraptor" + suffix + ".xml found.");
148: return true;
149: }
150: try {
151: XMLConfigurationLoader loader = new XMLConfigurationLoader();
152: VRaptorConfiguration config = loader
153: .read(new InputStreamReader(file));
154: config.readManagers(web);
155: config.readComponents(web);
156: return config.isAutoDiscover();
157: } finally {
158: try {
159: file.close();
160: } catch (IOException e) {
161: throw new ConfigException(e.getMessage(), e);
162: }
163: }
164: }
165:
166: private void autoDiscoverComponents() throws ConfigException {
167: long initTime = System.currentTimeMillis();
168: readDirectory();
169: if (LOG.isDebugEnabled()) {
170: long totalTime = System.currentTimeMillis() - initTime;
171: LOG.debug(String.format("auto-discover total time: %d ms",
172: totalTime));
173: }
174: }
175:
176: private InputStream getXMLFile(String suffix) {
177: return VRaptorServlet.class
178: .getResourceAsStream(VRAPTOR_XML_LOCATION + "vraptor"
179: + suffix + ".xml");
180: }
181:
182: }
|