View Javadoc

1   /*** 
2    * 
3    * Copyright 2004 Protique Ltd
4    * 
5    * Licensed under the Apache License, Version 2.0 (the "License"); 
6    * you may not use this file except in compliance with the License. 
7    * You may obtain a copy of the License at 
8    * 
9    * http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License. 
16   * 
17   **/
18  package org.activeio;
19  
20  import java.io.BufferedInputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.net.URI;
24  import java.util.HashMap;
25  import java.util.Properties;
26  
27  import org.activeio.adapter.AsynchToSynchChannelFactoryAdaptor;
28  import org.activeio.adapter.SynchToAsynchChannelFactoryAdaptor;
29  
30  import EDU.oswego.cs.dl.util.concurrent.Executor;
31  import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
32  import EDU.oswego.cs.dl.util.concurrent.ThreadFactory;
33  
34  /***
35   * A {@see ChannelFactory}uses the requested URI's scheme to determine the
36   * actual {@see org.activeio.SynchChannelFactory}or
37   * {@see org.activeio.AsynchChannelFactory}implementation to use to create it's
38   * {@see org.activeio.Channel}s and {@see org.activeio.ChannelServer}s.
39   * 
40   * Each URI scheme that {@see ChannelFactory}object handles will have a
41   * properties file located at: "META-INF/org.activeio.ChannelFactory/{scheme}".
42   * 
43   */
44  public class ChannelFactory implements SynchChannelFactory, AsynchChannelFactory {
45  
46      private final HashMap synchChannelFactoryMap = new HashMap();
47      private final HashMap asynchChannelFactoryMap = new HashMap();
48  
49      
50      static public final Executor DEFAULT_EXECUTOR = new PooledExecutor();
51      static {
52          ((PooledExecutor) DEFAULT_EXECUTOR).setThreadFactory(new ThreadFactory() {
53              public Thread newThread(Runnable run) {
54                  Thread thread = new Thread(run);
55                  thread.setDaemon(true);
56                  return thread;
57              }
58          });
59      }
60  
61      static private class FactoryFinder {
62          private String path;
63  
64          public FactoryFinder(String path) {
65              this.path = path;
66          }
67  
68          /***
69           * Creates a new instance of the given key
70           * 
71           * @param key
72           *            is the key to add to the path to find a text file
73           *            containing the factory name
74           * @return a newly created instance
75           */
76          public Object newInstance(String key) throws IllegalAccessException, InstantiationException, IOException,
77                  ClassNotFoundException {
78              return newInstance(key, null);
79          }
80  
81          public Object newInstance(String key, String propertyPrefix) throws IllegalAccessException,
82                  InstantiationException, IOException, ClassNotFoundException {
83              return newInstance(doFindFactoryProperies(key), propertyPrefix);
84          }
85  
86          private Object newInstance(Properties properties, String propertyPrefix) throws ClassNotFoundException,
87                  InstantiationException, IllegalAccessException, IOException {
88  
89              if (propertyPrefix == null)
90                  propertyPrefix = "";
91  
92              String className = properties.getProperty(propertyPrefix + "class");
93              if (className == null) {
94                  throw new IOException("Expected property is missing: " + propertyPrefix + "class");
95              }
96              Class clazz;
97              try {
98                  clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
99              } catch (ClassNotFoundException e) {
100                 clazz = getClass().getClassLoader().loadClass(className);
101             }
102 
103             // We could use the properties to pass constructor args or set
104             // properties on the object.
105             return clazz.newInstance();
106         }
107 
108         private Properties doFindFactoryProperies(String key) throws IOException, ClassNotFoundException {
109             String uri = path + key;
110 
111             // lets try the thread context class loader first
112             InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri);
113             if (in == null) {
114                 in = getClass().getClassLoader().getResourceAsStream(uri);
115                 if (in == null) {
116                     throw new IOException("Could not find factory class for resource: " + uri);
117                 }
118             }
119 
120             // lets load the file
121             BufferedInputStream reader = null;
122             try {
123                 reader = new BufferedInputStream(in);
124                 Properties properties = new Properties();
125                 properties.load(reader);
126                 return properties;
127             } finally {
128                 try {
129                     reader.close();
130                 } catch (Exception e) {
131                 }
132             }
133         }
134     }
135 
136     private static FactoryFinder finder = new FactoryFinder("META-INF/org.activeio.ChannelFactory/");
137 
138     public SynchChannel openSynchChannel(URI location) throws IOException {
139         SynchChannelFactory factory = getSynchChannelFactory(location.getScheme());
140         return factory.openSynchChannel(location);
141     }
142 
143     public SynchChannelServer bindSynchChannel(URI location) throws IOException {
144         SynchChannelFactory factory = getSynchChannelFactory(location.getScheme());
145         return factory.bindSynchChannel(location);
146     }
147 
148     public AsynchChannel openAsynchChannel(URI location) throws IOException {
149         AsynchChannelFactory factory = getAsynchChannelFactory(location.getScheme());
150         return factory.openAsynchChannel(location);
151     }
152 
153     public AsynchChannelServer bindAsynchChannel(URI location) throws IOException {
154         AsynchChannelFactory factory = getAsynchChannelFactory(location.getScheme());
155         return factory.bindAsynchChannel(location);
156     }
157 
158     private SynchChannelFactory getSynchChannelFactory(String protocol) throws IOException {
159         try {
160             SynchChannelFactory rc = (SynchChannelFactory) synchChannelFactoryMap.get(protocol);
161             if (rc == null) {
162                 try {
163                     rc = (SynchChannelFactory) finder.newInstance(protocol, "SynchChannelFactory.");
164                 } catch (Throwable original) {
165                     // try to recovery by using AsynchChannelFactory and adapt
166                     // it to be synch.
167                     try {
168                         AsynchChannelFactory f = (AsynchChannelFactory) finder.newInstance(protocol,
169                                 "AsynchChannelFactory.");
170                         rc = AsynchToSynchChannelFactoryAdaptor.adapt(f);
171                     } catch (Throwable e) {
172                         // Recovery strategy failed.. throw original exception.
173                         throw original;
174                     }
175                 }
176                 synchChannelFactoryMap.put(protocol, rc);
177             }
178             return rc;
179         } catch (Throwable e) {
180             throw (IOException) new IOException("Could not load a SynchChannelFactory for protcol: " + protocol
181                     + ", reason: " + e).initCause(e);
182         }
183     }
184 
185     private AsynchChannelFactory getAsynchChannelFactory(String protocol) throws IOException {
186         try {
187             AsynchChannelFactory rc = (AsynchChannelFactory) asynchChannelFactoryMap.get(protocol);
188             if (rc == null) {
189 
190                 try {
191                     rc = (AsynchChannelFactory) finder.newInstance(protocol, "AsynchChannelFactory.");
192                 } catch (Throwable original) {
193                     // try to recovery by using SynchChannelFactory and adapt it
194                     // to be asynch.
195                     try {
196                         SynchChannelFactory f = (SynchChannelFactory) finder.newInstance(protocol,
197                                 "SynchChannelFactory.");
198                         rc = SynchToAsynchChannelFactoryAdaptor.adapt(f);
199                     } catch (Throwable e) {
200                         // Recovery strategy failed.. throw original exception.
201                         throw original;
202                     }
203                 }
204 
205                 asynchChannelFactoryMap.put(protocol, rc);
206             }
207             return rc;
208         } catch (Throwable e) {
209             throw (IOException) new IOException("Could not load a AsynchChannelFactory for protcol: " + protocol
210                     + ", reason: " + e).initCause(e);
211         }
212     }
213 
214 }