001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.nio.channels.spi;
019:
020: import java.io.BufferedReader;
021: import java.io.IOException;
022: import java.io.InputStreamReader;
023: import java.net.URL;
024: import java.nio.channels.Channel;
025: import java.nio.channels.DatagramChannel;
026: import java.nio.channels.Pipe;
027: import java.nio.channels.ServerSocketChannel;
028: import java.nio.channels.SocketChannel;
029: import java.security.AccessController;
030: import java.security.PrivilegedAction;
031: import java.util.Enumeration;
032:
033: import org.apache.harmony.luni.platform.Platform;
034: import org.apache.harmony.nio.internal.SelectorProviderImpl;
035:
036: /**
037: * Provider for nio selector and selectable channel.
038: * <p>
039: * The provider can be got by system property or the configuration file in a jar
040: * file, if not, the system default provider will return. The main function of
041: * this class is to return the instance of implementation class of
042: * <code>DatagramChannel</code>, <code>Pipe</code>, <code>Selector</code> ,
043: * <code>ServerSocketChannel</code>, and <code>SocketChannel</code>. All
044: * the methods of this class are multi-thread safe.
045: * </p>
046: */
047: public abstract class SelectorProvider extends Object {
048:
049: private static final String SYMBOL_COMMENT = "#"; //$NON-NLS-1$
050:
051: private static final String PROVIDER_IN_SYSTEM_PROPERTY = "java.nio.channels.spi.SelectorProvider"; //$NON-NLS-1$
052:
053: private static final String PROVIDER_IN_JAR_RESOURCE = "META-INF/services/java.nio.channels.spi.SelectorProvider"; //$NON-NLS-1$
054:
055: private static SelectorProvider provider = null;
056:
057: private static Channel inheritedChannel;
058:
059: /**
060: * Constructor for this class.
061: *
062: * @throws SecurityException
063: * If there is a security manager, and it denies
064: * RuntimePermission("selectorProvider").
065: */
066: protected SelectorProvider() {
067: super ();
068: if (null != System.getSecurityManager()) {
069: System.getSecurityManager().checkPermission(
070: new RuntimePermission("selectorProvider")); //$NON-NLS-1$
071: }
072: }
073:
074: /**
075: * Get the provider by following steps in the first calling.
076: * <p>
077: * <ul>
078: * <li> If the system property "java.nio.channels.spi.SelectorProvider" is
079: * set, the value of this property is the class name of the return provider.
080: * </li>
081: * <li>If there is a provider-configuration file named
082: * "java.nio.channels.spi.SelectorProvider" in META-INF/services of some jar
083: * file valid in the system class loader, the first class name is the return
084: * provider's class name. </li>
085: * <li> Otherwise, a system default provider will be returned. </li>
086: * </ul>
087: * </p>
088: *
089: * @return The provider.
090: */
091: synchronized public static SelectorProvider provider() {
092: if (null == provider) {
093: provider = loadProviderByProperty();
094: if (null == provider) {
095: provider = loadProviderByJar();
096: }
097: if (null == provider) {
098: provider = AccessController
099: .doPrivileged(new PrivilegedAction<SelectorProvider>() {
100: public SelectorProvider run() {
101: return new SelectorProviderImpl();
102: }
103: });
104: }
105: }
106: return provider;
107: }
108:
109: /*
110: * load the provider in the jar file of class path.
111: */
112: static SelectorProvider loadProviderByJar() {
113: Enumeration<URL> enumeration = null;
114:
115: ClassLoader classLoader = AccessController
116: .doPrivileged(new PrivilegedAction<ClassLoader>() {
117: public ClassLoader run() {
118: return ClassLoader.getSystemClassLoader();
119: }
120: });
121: try {
122: enumeration = classLoader
123: .getResources(PROVIDER_IN_JAR_RESOURCE);
124: } catch (IOException e) {
125: throw new Error(e);
126: }
127: if (null == enumeration) {
128: return null;
129: }
130: // for every jar, read until we find the provider name.
131: while (enumeration.hasMoreElements()) {
132: BufferedReader br = null;
133: String className = null;
134: try {
135: br = new BufferedReader(new InputStreamReader(
136: (enumeration.nextElement()).openStream()));
137: } catch (Exception e) {
138: continue;
139: }
140: try {
141: // only the first class is loaded ,as spec says, not the same as
142: // we do before.
143: while ((className = br.readLine()) != null) {
144: className = className.trim();
145: int siteComment = className.indexOf(SYMBOL_COMMENT);
146: className = (-1 == siteComment) ? className
147: : className.substring(0, siteComment);
148: if (0 < className.length()) {
149: return (SelectorProvider) classLoader
150: .loadClass(className).newInstance();
151: }
152: }
153: } catch (Exception e) {
154: throw new Error(e);
155: } finally {
156: try {
157: br.close();
158: } catch (IOException ioe) {
159: // Ignore
160: }
161: }
162: }
163: return null;
164: }
165:
166: /*
167: * Load by system property.
168: */
169: static SelectorProvider loadProviderByProperty() {
170: return AccessController
171: .doPrivileged(new PrivilegedAction<SelectorProvider>() {
172: public SelectorProvider run() {
173: try {
174: final String className = System
175: .getProperty(PROVIDER_IN_SYSTEM_PROPERTY);
176: if (null != className) {
177: Class<?> spClass = ClassLoader
178: .getSystemClassLoader()
179: .loadClass(className);
180: return (SelectorProvider) spClass
181: .newInstance();
182: }
183: return null;
184: } catch (Exception e) {
185: throw new Error(e);
186: }
187: }
188: });
189: }
190:
191: /**
192: * Create a new open <code>DatagramChannel</code>.
193: *
194: * @return The channel.
195: * @throws IOException
196: * If some I/O exception occurred.
197: */
198: public abstract DatagramChannel openDatagramChannel()
199: throws IOException;
200:
201: /**
202: * Create a new <code>Pipe</code>.
203: *
204: * @return The pipe.
205: * @throws IOException
206: * If some I/O exception occurred.
207: */
208: public abstract Pipe openPipe() throws IOException;
209:
210: /**
211: * Create a new selector.
212: *
213: * @return The selector.
214: * @throws IOException
215: * If some I/O exception occurred.
216: */
217: public abstract AbstractSelector openSelector() throws IOException;
218:
219: /**
220: * Create a new open <code>ServerSocketChannel</code>.
221: *
222: * @return The channel.
223: * @throws IOException
224: * If some I/O exception occurred.
225: */
226: public abstract ServerSocketChannel openServerSocketChannel()
227: throws IOException;
228:
229: /**
230: * Create a new open <code>SocketChannel</code>.
231: *
232: * @return The channel.
233: * @throws IOException
234: * If some I/O exception occurred.
235: */
236: public abstract SocketChannel openSocketChannel()
237: throws IOException;
238:
239: /**
240: * Answer the channel inherited from the instance which created this JVM.
241: *
242: * @return The channel.
243: * @throws IOException
244: * If some I/O exception occurred.
245: * @throws SecurityException
246: * If there is a security manager, and it denies
247: * RuntimePermission("selectorProvider").
248: */
249: public Channel inheritedChannel() throws IOException {
250: if (null == inheritedChannel) {
251: inheritedChannel = Platform.getNetworkSystem()
252: .inheritedChannel();
253: }
254: return inheritedChannel;
255: }
256: }
|