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 javax.sql.rowset.spi;
019:
020: import java.io.FileInputStream;
021: import java.io.IOException;
022: import java.util.Enumeration;
023: import java.util.Hashtable;
024: import java.util.Properties;
025: import java.util.logging.Level;
026: import java.util.logging.Logger;
027:
028: import javax.naming.Binding;
029: import javax.naming.Context;
030: import javax.naming.NamingEnumeration;
031: import javax.naming.NamingException;
032:
033: import org.apache.harmony.sql.internal.nls.Messages;
034:
035: /**
036: * A singleton factory class that generates SyncProvider instances. There are
037: * three places to search SyncProviders: system properties, resource files and
038: * the JNDI context.
039: *
040: * Applications can also use it to add and remove SyncProviders at runtime.
041: */
042: public class SyncFactory {
043: public static String ROWSET_SYNC_PROVIDER = "rowset.provider.classname"; //$NON-NLS-1$
044:
045: public static String ROWSET_SYNC_VENDOR = "rowset.provider.vendor"; //$NON-NLS-1$
046:
047: public static String ROWSET_SYNC_PROVIDER_VERSION = "rowset.provider.version"; //$NON-NLS-1$
048:
049: private static SyncFactory instance = new SyncFactory();
050:
051: private static final String ROWSET_PROPERTIES = "rowset.properties"; //$NON-NLS-1$
052:
053: private static Hashtable<String, SyncProvider> providers = new Hashtable<String, SyncProvider>();
054:
055: private static Context ctx;
056:
057: private static String resLocation;
058:
059: // TODO: the default provider hasn't been implemented yet
060: private static String defaultProviderName = "org.apache.harmony.sql.internal.rowset.HYOptimisticProvider"; //$NON-NLS-1$
061:
062: private static ProviderImpl defaultProvider = new ProviderImpl(
063: defaultProviderName);
064:
065: private static Logger logger;
066:
067: private static boolean initialized;
068:
069: static {
070: // the properties file is located at ${java.home}/lib/rowset.properties
071: // In RI, it is in ${java.home}/lib/resources.jar/rowset.properties
072: resLocation = new StringBuilder(System.getProperty("java.home")).append( //$NON-NLS-1$
073: System.getProperty("file.separator")).append("lib").append( //$NON-NLS-1$ //$NON-NLS-2$
074: System.getProperty("file.separator")).append(ROWSET_PROPERTIES) //$NON-NLS-1$
075: .toString();
076: }
077:
078: private static String getProviderProperties(Properties prop,
079: String inital, int index) {
080: StringBuilder builder = new StringBuilder(inital);
081: builder.append("."); //$NON-NLS-1$
082: builder.append(index);
083:
084: return prop.getProperty(builder.toString());
085: }
086:
087: private static Enumeration<SyncProvider> getRegisteredProvidersImpl() {
088: if (!initialized) {
089: // 1. load from System property
090: String rowsetPropStr = System
091: .getProperty(ROWSET_SYNC_PROVIDER);
092: if (rowsetPropStr != null) {
093: String[] sysProviders = rowsetPropStr.split(":"); //$NON-NLS-1$
094: for (String sysProvider : sysProviders) {
095: providers.put(sysProvider, new ProviderImpl(
096: sysProvider));
097: }
098: }
099:
100: // 2. looks in the resource file
101: Properties rowsetProp = new Properties();
102: try {
103: FileInputStream resInput = new FileInputStream(
104: resLocation);
105: rowsetProp.load(resInput);
106: resInput.close();
107: } catch (IOException e) {
108: // ignore
109: }
110: int index = 0;
111: while (true) {
112: String className = getProviderProperties(rowsetProp,
113: ROWSET_SYNC_PROVIDER, index);
114: if (null == className) {
115: break;
116: }
117:
118: String vendor = getProviderProperties(rowsetProp,
119: ROWSET_SYNC_VENDOR, index);
120: String version = getProviderProperties(rowsetProp,
121: ROWSET_SYNC_PROVIDER_VERSION, index);
122: providers.put(className, new ProviderImpl(className,
123: vendor, version));
124: index++;
125: }
126:
127: // 3. checks the JNDI context that has been set
128: if (ctx != null) {
129: try {
130: NamingEnumeration<Binding> bindings = ctx
131: .listBindings("");
132: while (bindings.hasMore()) {
133: Binding bind = bindings.next();
134: providers.put(bind.getName(),
135: (SyncProvider) bind.getObject());
136: }
137: } catch (NamingException e) {
138: // ignore
139: }
140: }
141: initialized = true;
142: }
143: return providers.elements();
144: }
145:
146: /**
147: * Initializes the registeration table if it is still empty.
148: */
149: private static void initProviders() {
150: if (providers.isEmpty()) {
151: SyncFactory.getRegisteredProvidersImpl();
152: }
153: }
154:
155: // This class does not have public constructor
156: private SyncFactory() {
157: // do nothing
158: }
159:
160: /**
161: * Adds the corresponding SyncProvider implementation into SyncFactory's
162: * registeration table.
163: *
164: * @param providerID -
165: * The unique ID of the SyncProvider implementation
166: * @throws SyncFactoryException -
167: * if the parameter providerID is null or empty.
168: */
169: public static void registerProvider(String providerID)
170: throws SyncFactoryException {
171: if (null == providerID || providerID.length() == 0) {
172: throw new SyncFactoryException();
173: }
174: initProviders();
175: providers.put(providerID, new ProviderImpl(providerID));
176: }
177:
178: /**
179: * Answers the singleton instance of the SyncFactory.
180: *
181: * @return - the singleton instance of the SyncFactory.
182: */
183: public static SyncFactory getSyncFactory() {
184: return instance;
185: }
186:
187: /**
188: * Removes the SyncProvider from SyncFactory's registeration table.
189: *
190: * @param providerID -
191: * The unique ID of the SyncProvider implementation
192: * @throws SyncFactoryException -
193: * Removes a unregistered provider.
194: */
195: public static void unregisterProvider(String providerID)
196: throws SyncFactoryException {
197: initProviders();
198: if (null == providers.remove(providerID)) {
199: throw new SyncFactoryException();
200: }
201: }
202:
203: /**
204: * Answers the specific SyncProvider implementation according to the given
205: * String ID. When the given ID does not exist in the registeration table,
206: * it returns the default provider.
207: *
208: * @param providerID -
209: * The unique ID of the SyncProvider implementation
210: * @return - The specific SyncProvider instance
211: * @throws SyncFactoryException
212: */
213: public static SyncProvider getInstance(String providerID)
214: throws SyncFactoryException {
215: initProviders();
216: SyncProvider provider = providers.get(providerID);
217: if (null == provider) {
218: return defaultProvider.getImpl();
219: }
220: return ((ProviderImpl) provider).getImpl();
221: }
222:
223: /**
224: * Answers the collection of SyncProvider instances that can be retrieved.
225: * RowSet implementation is able to use any member in this enumeration.
226: *
227: * @return - the collection of SyncProvider registered in SyncFactory.
228: * @throws SyncFactoryException
229: */
230: public static Enumeration<SyncProvider> getRegisteredProviders()
231: throws SyncFactoryException {
232: return getRegisteredProvidersImpl();
233: }
234:
235: /**
236: * Sets the logging object. All of the SyncProvider implementations can log
237: * events to the object. This object can be retrieved by the getLogger
238: * method.
239: *
240: * @param logger -
241: * the logging object
242: */
243: public static void setLogger(Logger logger) {
244: SyncFactory.logger = logger;
245: }
246:
247: /**
248: * Sets the logging object and its corresponding logging level. All of the
249: * SyncProvider implementations can log events to the object. This object
250: * can be retrieved by the getLogger method.
251: *
252: * @param logger -
253: * the logging object
254: */
255: public static void setLogger(Logger logger, Level level) {
256: SyncFactory.logger = logger;
257: SyncFactory.logger.setLevel(level);
258: }
259:
260: /**
261: * Answers the Logger instance used for recording events triggered by
262: * SyncProvider.
263: *
264: * @return - the logging object
265: * @throws SyncFactoryException -
266: * if the logger is null.
267: */
268: public static Logger getLogger() throws SyncFactoryException {
269: if (null == logger) {
270: throw new SyncFactoryException(Messages.getString("sql.44")); //$NON-NLS-1$
271: }
272: return logger;
273: }
274:
275: /**
276: * Sets the JNDI context from which the implementation of SyncProvider can
277: * be got.
278: *
279: * @param ctx -
280: * the JNDI context
281: * @throws SyncFactoryException -
282: * if the given JNDI context is null
283: */
284: public static void setJNDIContext(Context ctx)
285: throws SyncFactoryException {
286: if (null == ctx) {
287: throw new SyncFactoryException(Messages.getString("sql.41")); //$NON-NLS-1$
288: }
289: SyncFactory.ctx = ctx;
290: }
291: }
|