View Javadoc

1   /*
2    * Copyright 2001-2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.nxqd.xmldb;
17  
18  import java.util.List;
19  import java.util.ArrayList;
20  import java.util.logging.Level;
21  import java.util.logging.Logger;
22  
23  import net.sf.nxqd.NxqdManager;
24  import net.sf.nxqd.NxqdConsumer;
25  import net.sf.nxqd.NxqdException;
26  import net.sf.nxqd.NxqdContainer;
27  import org.xmldb.api.base.Collection;
28  import org.xmldb.api.base.Database;
29  import org.xmldb.api.base.XMLDBException;
30  import org.xmldb.api.base.ErrorCodes;
31  
32  
33  /**
34   * The class <code>NxqdDatabase</code> is the Xml:DB driver for
35   * communicating with the  Nxqd Apache module.
36   *
37   * @see org.xmldb.api.base.Database
38   *
39   * @author <a href="mailto:webhiker@sourceforge.net">webhiker</a>
40   * @version 1.0
41   */
42  public class NxqdDatabase extends NxqdConsumer implements Database {
43  
44      /**
45       * The variable <code>logger</code> is used for logging events.
46       *
47       */
48      private static Logger logger = Logger.getLogger(NxqdDatabase.class.getName());
49      /**
50       * The <code>NXQD_NAME</code> constant is used to construct a Xml:DB URI
51       * to connect to the Nxqd server.
52       */
53      public  static final String NXQD_NAME         = "nxqd";
54      public  static final String NXQD_ROOT         = "db";
55      public  static final String NXQD_INTERNAL_SEP = "-+-";
56  
57      /**
58       * The a new <code>NxqdDatabase</code> constructor creates a new instance
59       * of this driver.
60       *
61       */
62      public NxqdDatabase() {
63          super();
64      }
65  
66      /**
67       * @see org.xmldb.api.base.Database#getName()
68       */
69      public final String getName() throws XMLDBException {
70          return new String(NXQD_NAME);
71      }
72  
73      /**
74       * @see org.xmldb.api.base.Database#getCollection(java.lang.String,
75       * java.lang.String, java.lang.String)
76       */
77      public final Collection getCollection(final String uri,
78  					  final String userName,
79  					  final String passWord)
80  	throws XMLDBException {
81  	try {
82  	    logger.fine("getCollection("+uri+","+userName+","+passWord+")");
83  	    setNxqdManager(new NxqdManager(parseHost(uri),
84  					   parsePort(uri)));
85  	    String collectionName = extractCollectionName(uri);
86  	    String containerName = encodePath(extractCollectionPath(uri));
87  	    // autocreate the root collection, but first rename it to special internal name
88  	    NxqdContainer container;
89  	    if (collectionName.equals(NXQD_ROOT)) {
90  		if (getNxqdManager().containerExists(containerName)) {
91  		    container = getNxqdManager().getContainer(containerName);
92  		} else {
93  		    container = getNxqdManager().createContainer(containerName);
94  		}
95  	    } else {
96  		container = getNxqdManager().getContainer(containerName);
97  	    }
98  	    return new NxqdCollection(collectionName,
99  				      this,
100 				      container,
101 				      getParentCollectionFromContainerName(containerName));
102 	} catch (NxqdException ne) {
103 	    throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
104 				     "Error getting Collection :" + ne.getMessage(),
105 				     ne);
106 	}
107     }
108 
109     protected Collection createCollection(String collectionName, NxqdCollection parent) throws XMLDBException {
110 	try {
111 	    logger.fine("createCollection("+collectionName+","+parent.getName()+")");
112 	    NxqdContainer container = getNxqdManager().createContainer(parent.getContainer().getName()+NXQD_INTERNAL_SEP+collectionName);
113 	    
114 	    NxqdCollection newCollection = new NxqdCollection(collectionName,
115 							      this,
116 							      container,
117 							      parent);
118 	    return newCollection;
119 	} catch (NxqdException ne) {
120 	    throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
121 				     "Error creating Collection :" + ne.getMessage(),
122 				     ne);
123 	}
124     }
125 
126     protected Collection getChildCollection(String collectionName, NxqdCollection parent) throws XMLDBException {
127 	try {
128 	    logger.fine("getChildCollection("+collectionName+","+parent.getName()+")");
129 	    NxqdContainer container;
130 	    // root is a special case
131 	    if (collectionName.equals(NXQD_ROOT)) {
132 		container = getNxqdManager().getContainer(NXQD_ROOT);
133 	    }
134 	    else {
135 		container = getNxqdManager().getContainer(parent.getContainer().getName()+NXQD_INTERNAL_SEP+collectionName);
136 	    }
137 
138 	    return new NxqdCollection(collectionName,
139 				      this,
140 				      container,
141 				      parent);
142 	} catch (NxqdException ne) {
143 	    return null;
144 	}
145     }
146     
147     /**
148      * The <code>getCollectionFromContainerName</code> method returns the Collection specified by
149      * the containerName. Note, this collectionName is the actual name name of the
150      * underlying container object.
151      *
152      * @param containerName a <code>String</code> value
153      * @return a <code>Collection</code> value
154      * @exception XMLDBException if an error occurs
155      */
156     protected NxqdCollection getCollectionFromContainerName(final String containerName) throws XMLDBException {
157      	try {
158 	    logger.fine("getCollectionFromContainerName("+containerName+")");
159      	    NxqdContainer container = getNxqdManager().getContainer(containerName);
160      	    String collectionName;
161      	    // special case of root
162      	    if (containerName.equals(NXQD_ROOT)) {
163      		collectionName = NXQD_ROOT;
164     	    }
165      	    else {
166      		// strip off the parent path info
167      		collectionName = containerName.substring(containerName.lastIndexOf(NXQD_INTERNAL_SEP)+NXQD_INTERNAL_SEP.length(),
168      							 containerName.length());
169      	    }
170 	    return new NxqdCollection(collectionName,
171 				      this,
172 				      container,
173 				      getParentCollectionFromContainerName(containerName));
174      	} catch (NxqdException ne) {
175      	    throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
176      				     "Error getting Collection :" + ne.getMessage(),
177      				     ne);
178      	}
179     }
180 
181     /**
182      * The <code>getCollectionFromContainerName</code> method returns the Collection specified by
183      * the containerName. Note, this collectionName is the actual name name of the
184      * underlying container object.
185      *
186      * @param containerName a <code>String</code> value
187      * @return a <code>Collection</code> value
188      * @exception XMLDBException if an error occurs
189      */
190     protected NxqdCollection getParentCollectionFromContainerName(final String containerName) throws XMLDBException {
191      	try {
192      	    NxqdContainer container = getNxqdManager().getContainer(containerName);
193      	    String collectionName;
194      	    // special case of root
195      	    if (containerName.equals(NXQD_ROOT)) {
196      		collectionName = NXQD_ROOT;
197 		return new NxqdCollection(collectionName,
198 					  this,
199 					  container, 
200 					  null);
201     	    }
202      	    else {
203      		// strip off the child path info
204      		collectionName = containerName.substring(0,
205 							 container.getName().lastIndexOf(NXQD_INTERNAL_SEP));
206 
207 		return new NxqdCollection(collectionName, 
208 					  this,
209 					  container, 
210 					  getParentCollectionFromContainerName(collectionName));
211      	    }
212 
213      	} catch (NxqdException ne) {
214      	    throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
215      				     "Error getting Collection :" + ne.getMessage(),
216      				     ne);
217      	}
218     }
219     
220     protected void deleteCollection(String collectionName, NxqdCollection parent) throws XMLDBException {
221 	try {
222 	    getNxqdManager().deleteContainer(parent.getContainer().getName()+NXQD_INTERNAL_SEP+collectionName);
223 	} catch (NxqdException ne) {
224 	    throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
225 				     "Error deleting Collection :" + ne.getMessage(),
226 				     ne);
227 	}
228     }
229 
230     protected List listChildCollections(NxqdCollection collection) throws XMLDBException {
231 	try {
232 	    logger.fine("listChildCollections("+collection.getName()+")");
233 	    List allCollections = getNxqdManager().listContainers();
234 	    // now find any matching the parent string path
235 	    String name = collection.getContainer().getName();
236 	    List childCollections = new ArrayList();
237 	    String currentCollection, parentName, temp;
238 	    parentName = collection.getContainer().getName();
239 	    for (int i = 0; i < allCollections.size(); i++) {
240 		currentCollection = allCollections.get(i).toString();
241 		if (currentCollection.startsWith(name)) {
242 		    // don't add the parent itself
243 		    if (!currentCollection.equals(parentName)) {
244 			// don't add children of the children
245 			temp = currentCollection.substring(currentCollection.indexOf(parentName)+parentName.length()+NXQD_INTERNAL_SEP.length(),
246 							   currentCollection.length());
247 			if (temp.indexOf(NXQD_INTERNAL_SEP)<0) {
248 			    // trim off the parent root name
249 			    childCollections.add(temp);
250 			}
251 		    }
252 		}
253 	    }
254 	    return childCollections;
255 	} catch (NxqdException ne) {
256 	    throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
257 				     "Error listing child collections :" + ne.getMessage(),
258 				     ne);
259 	}
260     }
261 
262     /**
263      * @see org.xmldb.api.base.Database#acceptsURI(java.lang.String)
264      */
265     public final boolean acceptsURI(final String uri) throws XMLDBException {
266 	return uri.startsWith(NXQD_NAME + "://");
267     }
268 
269     /**
270      * @see org.xmldb.api.base.Database#getConformanceLevel()
271      */
272     public final String getConformanceLevel() throws XMLDBException {
273         return "1";
274     }
275 
276     /**
277      * @see org.xmldb.api.base.Configurable#getProperty(java.lang.String)
278      */
279     public final String getProperty(final String name) throws XMLDBException {
280         return System.getProperty(name);
281     }
282 
283     /**
284      * @see org.xmldb.api.base.Configurable#setProperty(java.lang.String,
285      * java.lang.String)
286      */
287     public final void setProperty(final String name,
288 				  final String value) throws XMLDBException {
289         System.setProperty(name, value);
290     }
291 
292     /**
293      * The <code>parseHost</code> method will extract the host value
294      * from the uri parameter.
295      *
296      * @param uri a <code>String</code> value
297      * @return a <code>String</code> value
298      */
299     public static String parseHost(final String uri) {
300 	String tag = "://";
301 	String parsedHost = uri.substring(uri.indexOf(NXQD_NAME + tag)
302 					  + NXQD_NAME.length() + tag.length(),
303 					  uri.length());
304 	// be flexible in case it something like nxqd://localhost:3306
305 	if (parsedHost.indexOf('/') > 0) {
306 	    parsedHost = parsedHost.substring(0, parsedHost.indexOf('/'));
307 	} else {
308 	    parsedHost = parsedHost.substring(0, parsedHost.length());
309 	}
310 
311 	// check if port was specified
312 	if (parsedHost.indexOf(':') > 0) {
313 	    parsedHost = parsedHost.substring(0, parsedHost.indexOf(':'));
314 	}
315 
316         if (parsedHost.length() < 2) {
317 	    parsedHost = "localhost";
318 	}
319 	return parsedHost;
320     }
321 
322     /**
323      * The <code>parseHost</code> method will extract the port value from
324      * the uri parameter.
325      *
326      * @param uri a <code>String</code> value
327      * @return a <code>String</code> value
328      */
329     public static String parsePort(final String uri) throws NxqdException {
330 	String tag = "://";
331 	String parsedPort = uri.substring(uri.indexOf(NXQD_NAME + tag)
332 					  + NXQD_NAME.length() + tag.length(),
333 					  uri.length());
334 	// be flexible in case it something like nxqd://localhost:3306
335 	if (parsedPort.indexOf('/') > 0) {
336 	    parsedPort = parsedPort.substring(0, parsedPort.indexOf('/'));
337 	} else {
338 	    parsedPort = parsedPort.substring(0, parsedPort.length());
339 	}
340 
341 	// check if port was specified
342 	if (parsedPort.indexOf(':') > 0) {
343 	    parsedPort = parsedPort.substring(parsedPort.indexOf(':') + 1,
344 					      parsedPort.length());
345 	    if (parsedPort.indexOf('/') > 0) {
346 		parsedPort = parsedPort.substring(0,  parsedPort.indexOf('/'));
347 	    }
348 	} else {
349 	    //parsedPort = NxqdManager.NXQD_PORT;
350 	    throw new NxqdException("No port was specified in the URI "+uri);
351 	}
352 
353 	return parsedPort;
354     }
355 
356     /**
357      * The <code>extractCollectionName</code> method will extract the Collection
358      * name from the uri parameter.
359      *
360      * @param uri a <code>String</code> value
361      * @return a <code>String</code> value
362      */
363     public static String extractCollectionName(final String uri) {
364 	String collectionName;
365 	int lastIndex = uri.lastIndexOf('/');
366 	if (lastIndex>0) {
367 	    collectionName = uri.substring(lastIndex+1,uri.length());
368 	}
369 	else {
370 	    collectionName = uri;
371 	}
372 	if ((collectionName.equals("/"))|
373 	    (collectionName.length()==0)) {
374 	    collectionName = NXQD_ROOT;
375 	}
376 	return collectionName;
377     }
378 
379     /**
380      * The <code>extractCollectionPath</code> method will extract the Collection
381      * path from the uri parameter.
382      *
383      * @param uri a <code>String</code> value
384      * @return a <code>String</code> value
385      */
386     public static String extractCollectionPath(final String uri) throws NxqdException {
387 	String port = parsePort(uri);
388 	int pathStart  =uri.indexOf(port)+port.length()+1;
389 	String collectionPath = uri.substring(pathStart,uri.length());
390 	if (collectionPath.length()==0) {
391 	    collectionPath = NXQD_ROOT;
392 	}
393 	return collectionPath;
394     }
395 
396     public static String encodePath(final String path) {
397 	return path.replace("/", 
398 			     NXQD_INTERNAL_SEP);
399     }
400 
401     public static String decodePath(final String path) {
402 	return path.replace(NXQD_INTERNAL_SEP,
403 			    "/");
404     }
405 
406 
407 }
408