001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.storage.implementation.database;
011:
012: import java.sql.*;
013:
014: import org.w3c.dom.*;
015: import org.xml.sax.InputSource;
016:
017: import org.mmbase.storage.*;
018:
019: import org.mmbase.util.ResourceLoader;
020: import org.mmbase.util.xml.DocumentReader;
021: import org.mmbase.util.logging.Logger;
022: import org.mmbase.util.logging.Logging;
023:
024: /**
025: * Represents a xml document that can be used to determine the database configuration resource,
026: * based on a database's metadata.
027: *
028: * @author Pierre van Rooden
029: * @since MMBase-1.7
030: * @version $Id: DatabaseStorageLookup.java,v 1.8 2006/09/25 14:08:45 michiel Exp $
031: */
032: public class DatabaseStorageLookup extends DocumentReader {
033:
034: private static final Logger log = Logging
035: .getLoggerInstance(DatabaseStorageLookup.class);
036:
037: private static String DATABASE_STORAGE_LOOKUP_RESOURCE_PATH_FALLBACK = "/org/mmbase/storage/implementation/database/resources/lookup.xml";
038: private static String DATABASE_STORAGE_LOOKUP_RESOURCE_PATH = "storage/databases/lookup.xml";
039:
040: /** Public ID of the Storage DTD version 1.0 */
041: public static final String PUBLIC_ID_DATABASE_STORAGE_LOOKUP_1_0 = "-//MMBase//DTD storage config 1.0//EN";
042: /** DTD resource filename of the Database DTD version 1.0 */
043: public static final String DTD_DATABASE_STORAGE_LOOKUP_1_0 = "storage_1_0.dtd";
044:
045: /** Public ID of the most recent Database DTD */
046: public static final String PUBLIC_ID_DATABASE_STORAGE_LOOKUP = PUBLIC_ID_DATABASE_STORAGE_LOOKUP_1_0;
047: /** DTD resource filename of the most Database DTD */
048: public static final String DTD_DATABASE_STORAGE_LOOKUP = DTD_DATABASE_STORAGE_LOOKUP_1_0;
049:
050: /**
051: * Register the Public Ids for DTDs used by StorageReader
052: * This method is called by XMLEntityResolver.
053: */
054: static {
055: org.mmbase.util.XMLEntityResolver.registerPublicID(
056: PUBLIC_ID_DATABASE_STORAGE_LOOKUP_1_0,
057: DTD_DATABASE_STORAGE_LOOKUP_1_0,
058: DatabaseStorageLookup.class);
059: }
060:
061: /**
062: * @since MMBase-1.8
063: */
064: private static InputSource getInputSource() {
065: InputSource is = null;
066: try {
067: is = ResourceLoader.getConfigurationRoot().getInputSource(
068: DATABASE_STORAGE_LOOKUP_RESOURCE_PATH);
069: } catch (java.io.IOException ioe) {
070: log.service(ioe);
071: }
072: if (is == null) { // 1.7 compatibility
073: is = new InputSource(
074: DatabaseStorageLookup.class
075: .getResourceAsStream(DATABASE_STORAGE_LOOKUP_RESOURCE_PATH_FALLBACK));
076: is
077: .setSystemId(DATABASE_STORAGE_LOOKUP_RESOURCE_PATH_FALLBACK);
078: return is;
079: } else {
080: return is;
081: }
082: }
083:
084: /**
085: * Constructor, accesses the storage lookup xml resource
086: */
087: DatabaseStorageLookup() {
088: super (getInputSource(), DocumentReader.validate(),
089: DatabaseStorageLookup.class);
090: }
091:
092: /**
093: * Obtain an path to a database configuration resource
094: * @param dmd the database meta data
095: * @return The database configuration resource, or <code>null</code> if it cannot be determined
096: */
097: String getResourcePath(DatabaseMetaData dmd) throws SQLException,
098: StorageConfigurationException {
099: Element root = document.getDocumentElement();
100: NodeList filterList = root.getElementsByTagName("filter");
101: for (int i = 0; i < filterList.getLength(); i++) {
102: Element filter = (Element) filterList.item(i);
103: String resourcePath = filter.getAttribute("resource");
104: if (match(filter, dmd)) {
105: log.service("Auto detection selected '" + resourcePath
106: + "' for the current database.");
107: return resourcePath;
108: }
109: }
110: // not found, return null
111: return null;
112: }
113:
114: /**
115: * Returns an given connection URL for a given Driver CLass. Or <code>null</code> if no such
116: * thing was defined in lookup.xml. In that case the configured URL in MMBase can be used.
117: *
118: * @since MMBase-1.8
119: */
120: String getMetaURL(Class clazz) {
121: Element root = document.getDocumentElement();
122: NodeList urlList = root.getElementsByTagName("url");
123: for (int i = 0; i < urlList.getLength(); i++) {
124: Element url = (Element) urlList.item(i);
125: String driverClass = url.getAttribute("driver-class");
126: if (clazz.getName().startsWith(driverClass)) {
127: return getNodeTextValue(url);
128: }
129: }
130: // not found, return null
131: return null;
132: }
133:
134: /**
135: * Tests if an given filterset applies
136: * @param filterNode The element containing all filters
137: * @param dmd the database meta data
138: * @return <code>true</code> when true, otherwise <code>false</code>
139: */
140: private boolean match(Element filterNode, DatabaseMetaData dmd)
141: throws SQLException, StorageConfigurationException {
142: NodeList conditionList = filterNode.getElementsByTagName("*");
143: boolean match = true;
144: for (int i = 0; match && i < conditionList.getLength(); i++) {
145: Element condition = (Element) conditionList.item(i);
146: String conditionName = condition.getTagName();
147: if (conditionName.equals("driver-class")) {
148: match = startMatch(condition, dmd.getConnection()
149: .getClass().getName());
150: } else if (conditionName.equals("driver-name")) {
151: match = match(condition, dmd.getDriverName());
152: } else if (conditionName.equals("driver-version")) {
153: match = match(condition, dmd.getDriverVersion());
154: } else if (conditionName.equals("database-product-name")) {
155: match = match(condition, dmd.getDatabaseProductName());
156: } else if (conditionName.equals("database-product-version")) {
157: match = match(condition, dmd
158: .getDatabaseProductVersion());
159: } else if (conditionName.equals("driver-major-version")) {
160: match = match(condition, dmd.getDriverMajorVersion());
161: } else if (conditionName.equals("driver-minor-version")) {
162: match = match(condition, dmd.getDriverMinorVersion());
163: } else {
164: throw new StorageConfigurationException(
165: "tag with name:'" + conditionName
166: + "' unknown.");
167: }
168: }
169: return match;
170: }
171:
172: /**
173: * Tests if an element value matches a value specified
174: * @param node the Element of which the body value has to be checked
175: * @param value the Value which has to be compared
176: * @return <code>true</code> when true, otherwise <code>false</code>
177: */
178: private boolean match(Element node, String value) {
179: return value.equals(getNodeTextValue(node));
180: }
181:
182: /**
183: * Tests if an string starts with the value of the node
184: * @param node the Element of which the body value has to be checked
185: * @param value the Value which has to be compared
186: * @return <code>true</code> when true, otherwise <code>false</code>
187: */
188: private boolean startMatch(Element node, String value) {
189: return value.startsWith(getNodeTextValue(node));
190: }
191:
192: /**
193: * Tests a condition from an attibute of the Element applies to the
194: * value of the element with the given int value
195: * @param node the Element of which the body value has to be checked
196: * @param value the Value which has to be compared
197: * @return <code>true</code> when true, otherwise <code>false</code>
198: */
199: private boolean match(Element node, int value)
200: throws StorageConfigurationException {
201: int foundValue = Integer.parseInt(getNodeTextValue(node));
202: String condition = node.getAttribute("condition");
203: if ((condition == null) || condition.equals("equals")) {
204: return foundValue == value;
205: } else if (condition.equals("from")) {
206: return foundValue <= value;
207: } else if (condition.equals("until")) {
208: return foundValue > value;
209: } else {
210: throw new StorageConfigurationException("condition: '"
211: + condition + "' unknown");
212: }
213: }
214: }
|