001: package dalma;
002:
003: import dalma.spi.EndPointFactory;
004:
005: import java.io.Serializable;
006: import java.io.IOException;
007: import java.util.Properties;
008: import java.util.Enumeration;
009: import java.util.WeakHashMap;
010: import java.util.Map;
011: import java.util.Collections;
012: import java.util.logging.Level;
013: import java.util.logging.Logger;
014: import java.net.URL;
015: import java.text.ParseException;
016:
017: /**
018: * Represents a gate through which {@link Conversation}s communicate with
019: * outer world.
020: *
021: * TODO: One engine may have more than one instances of the same endPoint
022: * (such as using multiple POP3 ports, etc.) How do we configure this?
023: * Perhaps by using Spring?
024: *
025: * TODO: allow JMX to monitor the endPoint status
026: *
027: * TODO: endPoint setting needs to be persistable. How do we do this?
028: * ports tend to have other native resources.
029: *
030: * TODO: check if the endPoint is really necessary at the engine level.
031: *
032: * @author Kohsuke Kawaguchi
033: */
034: public abstract class EndPoint implements Serializable {
035: private final String name;
036:
037: protected EndPoint(String name) {
038: this .name = name;
039: if (name == null)
040: throw new IllegalArgumentException();
041: }
042:
043: /**
044: * Gets the unique name that identifies this {@link EndPoint} within an {@link Engine}.
045: *
046: * @return
047: * always non-null valid object.
048: */
049: public String getName() {
050: return name;
051: }
052:
053: /**
054: * Creates a new {@link EndPoint} from a connection string.
055: *
056: * @param endPointName
057: * this value will be returned from {@link EndPoint#getName()}.
058: * Must not be null.
059: * @param endpointURL
060: * A connection string. Must not be null.
061: *
062: * @return always non-null valid object
063: * @throws ParseException
064: * if there was an error in the connection string.
065: */
066: public static EndPoint create(String endPointName,
067: String endpointURL) throws ParseException {
068: return Loader.get().createEndPoint(endPointName, endpointURL);
069: }
070:
071: /**
072: * The same as {@link #create(String, String)} except
073: * that it uses the given {@link ClassLoader} to locate {@link EndPoint} implementations.
074: */
075: public static EndPoint create(String endPointName,
076: String endpointURL, ClassLoader cl) throws ParseException {
077: return Loader.get(cl).createEndPoint(endPointName, endpointURL);
078: }
079:
080: private static final class Loader {
081: private static final Logger logger = Logger
082: .getLogger(Loader.class.getName());
083: private static final Map<ClassLoader, Loader> loaders = Collections
084: .synchronizedMap(new WeakHashMap<ClassLoader, Loader>());
085:
086: private final ClassLoader cl;
087: private final Properties endPointFactories = new Properties();
088:
089: static Loader get() {
090: return get(inferDefaultClassLoader());
091: }
092:
093: static Loader get(ClassLoader cl) {
094: Loader loader = loaders.get(cl);
095: if (loader == null) {
096: loaders.put(cl, loader = new Loader(cl));
097: }
098: return loader;
099: }
100:
101: private static ClassLoader inferDefaultClassLoader() {
102: ClassLoader cl = Thread.currentThread()
103: .getContextClassLoader();
104: if (cl == null)
105: cl = Loader.class.getClassLoader();
106: if (cl == null)
107: cl = ClassLoader.getSystemClassLoader();
108: return cl;
109: }
110:
111: public Loader(ClassLoader cl) {
112: this .cl = cl;
113:
114: try {
115: Enumeration<URL> resources = cl
116: .getResources("META-INF/services/dalma.spi.EndPointFactory");
117: while (resources.hasMoreElements()) {
118: URL url = resources.nextElement();
119: try {
120: endPointFactories.load(url.openStream());
121: } catch (IOException e) {
122: logger.log(Level.WARNING, "Unable to access "
123: + url, e);
124: }
125: }
126: } catch (IOException e) {
127: logger.log(Level.WARNING,
128: "failed to load endpoint factory list", e);
129: }
130: }
131:
132: public synchronized EndPoint createEndPoint(String name,
133: String endpointURL) throws ParseException {
134: int idx = endpointURL.indexOf(':');
135: if (idx < 0)
136: throw new ParseException("no scheme in " + endpointURL,
137: -1);
138: String scheme = endpointURL.substring(0, idx);
139:
140: EndPointFactory epf;
141: Object value = endPointFactories.get(scheme);
142: if (value == null)
143: throw new ParseException("unrecognized scheme "
144: + scheme, 0);
145: if (value instanceof String) {
146: try {
147: Class clazz = cl.loadClass((String) value);
148: Object o = clazz.newInstance();
149: if (!(o instanceof EndPointFactory)) {
150: logger.warning(clazz
151: + " is not an EndPointFactory");
152: }
153: epf = (EndPointFactory) o;
154: endPointFactories.put(scheme, epf);
155: } catch (ClassNotFoundException e) {
156: throw new NoClassDefFoundError(e.getMessage());
157: } catch (IllegalAccessException e) {
158: throw new IllegalAccessError(e.getMessage());
159: } catch (InstantiationException e) {
160: throw new InstantiationError(e.getMessage());
161: }
162: } else {
163: epf = (EndPointFactory) value;
164: }
165:
166: return epf.create(name, endpointURL);
167: }
168: }
169:
170: private static final long serialVersionUID = 1L;
171: }
|