ChannelFactory xref

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 }