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 package org.apache.commons.jxpath; 018 019 import java.io.BufferedReader; 020 import java.io.File; 021 import java.io.FileInputStream; 022 import java.io.IOException; 023 import java.io.InputStream; 024 import java.io.InputStreamReader; 025 import java.util.Properties; 026 027 /** 028 * Defines a factory API that enables applications to obtain a 029 * {@link JXPathContext} instance. To acquire a JXPathContext, first call the 030 * static {@link #newInstance} method of JXPathContextFactory. 031 * This method returns a concrete JXPathContextFactory. 032 * Then call {@link #newContext} on that instance. You will rarely 033 * need to perform these steps explicitly: usually you can call one of the 034 * <code>JXPathContex.newContext</code> methods, which will perform these steps 035 * for you. 036 * 037 * @see JXPathContext#newContext(Object) 038 * @see JXPathContext#newContext(JXPathContext,Object) 039 * 040 * @author Dmitri Plotnikov 041 * @version $Revision: 670727 $ $Date: 2008-06-23 15:10:38 -0500 (Mon, 23 Jun 2008) $ 042 */ 043 public abstract class JXPathContextFactory { 044 045 /** The default property */ 046 public static final String FACTORY_NAME_PROPERTY = 047 "org.apache.commons.jxpath.JXPathContextFactory"; 048 049 /** The default factory class */ 050 private static final String DEFAULT_FACTORY_CLASS = 051 "org.apache.commons.jxpath.ri.JXPathContextFactoryReferenceImpl"; 052 053 /** Avoid reading all the files when the findFactory 054 method is called the second time ( cache the result of 055 finding the default impl ) 056 */ 057 private static String factoryImplName = null; 058 059 /** 060 * Create a new JXPathContextFactory. 061 */ 062 protected JXPathContextFactory () { 063 064 } 065 066 /** 067 * Obtain a new instance of a <code>JXPathContextFactory</code>. 068 * This static method creates a new factory instance. 069 * This method uses the following ordered lookup procedure to determine 070 * the <code>JXPathContextFactory</code> implementation class to load: 071 * <ul> 072 * <li> 073 * Use the <code>org.apache.commons.jxpath.JXPathContextFactory</code> 074 * system property. 075 * </li> 076 * <li> 077 * Alternatively, use the JAVA_HOME (the parent directory where jdk is 078 * installed)/lib/jxpath.properties for a property file that contains the 079 * name of the implementation class keyed on 080 * <code>org.apache.commons.jxpath.JXPathContextFactory</code>. 081 * </li> 082 * <li> 083 * Use the Services API (as detailed in the JAR specification), if 084 * available, to determine the classname. The Services API will look 085 * for a classname in the file 086 * <code>META- INF/services/<i>org.apache.commons.jxpath. 087 * JXPathContextFactory</i></code> in jars available to the runtime. 088 * </li> 089 * <li> 090 * Platform default <code>JXPathContextFactory</code> instance. 091 * </li> 092 * </ul> 093 * 094 * Once an application has obtained a reference to a 095 * <code>JXPathContextFactory</code> it can use the factory to 096 * obtain JXPathContext instances. 097 * 098 * @return JXPathContextFactory 099 * @exception JXPathContextFactoryConfigurationError if the implementation 100 * is not available or cannot be instantiated. 101 */ 102 public static JXPathContextFactory newInstance() { 103 if (factoryImplName == null) { 104 factoryImplName = 105 findFactory(FACTORY_NAME_PROPERTY, DEFAULT_FACTORY_CLASS); 106 } 107 108 JXPathContextFactory factoryImpl; 109 try { 110 Class clazz = Class.forName(factoryImplName); 111 factoryImpl = (JXPathContextFactory) clazz.newInstance(); 112 } 113 catch (ClassNotFoundException cnfe) { 114 throw new JXPathContextFactoryConfigurationError(cnfe); 115 } 116 catch (IllegalAccessException iae) { 117 throw new JXPathContextFactoryConfigurationError(iae); 118 } 119 catch (InstantiationException ie) { 120 throw new JXPathContextFactoryConfigurationError(ie); 121 } 122 return factoryImpl; 123 } 124 125 /** 126 * Creates a new instance of a JXPathContext using the 127 * currently configured parameters. 128 * @param parentContext parent context 129 * @param contextBean Object bean 130 * @return JXPathContext 131 * @exception JXPathContextFactoryConfigurationError if a JXPathContext 132 * cannot be created which satisfies the configuration requested 133 */ 134 135 public abstract JXPathContext newContext( 136 JXPathContext parentContext, 137 Object contextBean); 138 139 // -------------------- private methods -------------------- 140 // This code is duplicated in all factories. 141 // Keep it in sync or move it to a common place 142 // Because it's small probably it's easier to keep it here 143 144 /** Temp debug code - this will be removed after we test everything 145 */ 146 private static boolean debug = false; 147 static { 148 try { 149 debug = System.getProperty("jxpath.debug") != null; 150 } 151 catch (SecurityException se) { //NOPMD 152 // This is ok 153 } 154 } 155 156 /** 157 * Private implementation method - will find the implementation 158 * class in the specified order. 159 * @param property Property name 160 * @param defaultFactory Default implementation, if nothing else is found 161 * 162 * @return class name of the JXPathContextFactory 163 */ 164 private static String findFactory(String property, String defaultFactory) { 165 // Use the factory ID system property first 166 try { 167 String systemProp = System.getProperty(property); 168 if (systemProp != null) { 169 if (debug) { 170 System.err.println( 171 "JXPath: found system property" + systemProp); 172 } 173 return systemProp; 174 } 175 176 } 177 catch (SecurityException se) { //NOPMD 178 // Ignore 179 } 180 181 // try to read from $java.home/lib/xml.properties 182 try { 183 String javah = System.getProperty("java.home"); 184 String configFile = 185 javah 186 + File.separator 187 + "lib" 188 + File.separator 189 + "jxpath.properties"; 190 File f = new File(configFile); 191 if (f.exists()) { 192 Properties props = new Properties(); 193 FileInputStream fis = new FileInputStream(f); 194 try { 195 props.load(fis); 196 } 197 finally { 198 if (fis != null) { 199 try { 200 fis.close(); 201 } 202 catch (IOException e) { //NOPMD 203 //swallow 204 } 205 } 206 } 207 String factory = props.getProperty(property); 208 if (factory != null) { 209 if (debug) { 210 System.err.println( 211 "JXPath: found java.home property " + factory); 212 } 213 return factory; 214 } 215 } 216 } 217 catch (IOException ex) { 218 if (debug) { 219 ex.printStackTrace(); 220 } 221 } 222 223 String serviceId = "META-INF/services/" + property; 224 // try to find services in CLASSPATH 225 try { 226 ClassLoader cl = JXPathContextFactory.class.getClassLoader(); 227 InputStream is = null; 228 if (cl == null) { 229 is = ClassLoader.getSystemResourceAsStream(serviceId); 230 } 231 else { 232 is = cl.getResourceAsStream(serviceId); 233 } 234 235 if (is != null) { 236 if (debug) { 237 System.err.println("JXPath: found " + serviceId); 238 } 239 BufferedReader rd = 240 new BufferedReader(new InputStreamReader(is)); 241 242 String factory = null; 243 try { 244 factory = rd.readLine(); 245 } 246 finally { 247 try { 248 rd.close(); 249 } 250 catch (IOException e) { //NOPMD 251 //swallow 252 } 253 } 254 255 if (factory != null && !"".equals(factory)) { 256 if (debug) { 257 System.err.println( 258 "JXPath: loaded from services: " + factory); 259 } 260 return factory; 261 } 262 } 263 } 264 catch (Exception ex) { 265 if (debug) { 266 ex.printStackTrace(); 267 } 268 } 269 return defaultFactory; 270 } 271 }