001: /******************************************************************
002: Copyright (c) 2004 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015:
016: Contributors:
017: 2004 Erik Bengtson - changed to use org.w3c.dom
018: 2004 Andy Jefferson - added table-owner. Changed table to be optional
019: ...
020: *****************************************************************/package org.jpox.store;
021:
022: import java.io.FileOutputStream;
023: import java.io.InputStreamReader;
024: import java.net.MalformedURLException;
025: import java.net.URL;
026: import java.util.Collection;
027: import java.util.HashSet;
028:
029: import javax.xml.parsers.DocumentBuilder;
030: import javax.xml.parsers.DocumentBuilderFactory;
031: import javax.xml.parsers.ParserConfigurationException;
032: import javax.xml.transform.OutputKeys;
033: import javax.xml.transform.Transformer;
034: import javax.xml.transform.TransformerFactory;
035: import javax.xml.transform.dom.DOMSource;
036: import javax.xml.transform.stream.StreamResult;
037:
038: import org.jpox.ObjectManagerFactoryImpl;
039: import org.jpox.ClassLoaderResolver;
040: import org.jpox.store.exceptions.DatastoreInitialisationException;
041: import org.jpox.util.JPOXLogger;
042: import org.w3c.dom.Document;
043: import org.w3c.dom.Element;
044: import org.w3c.dom.NodeList;
045: import org.xml.sax.InputSource;
046:
047: /**
048: * An auto-starter mechanism storing its definition in an XML file.
049: * Is independent of the datastore since it is stored as a file and not
050: * in the actual datastore.
051: *
052: * TODO Add a JPOXAutoStart DTD to validate the file automatically.
053: * TODO If we have one per PMF, need to guarantee unique naming of file.
054: *
055: * @version $Revision: 1.15 $
056: */
057: public class XMLAutoStarter extends AbstractAutoStartMechanism {
058: protected final URL fileUrl;
059: protected Document doc;
060: protected Element rootElement;
061:
062: /**
063: * Constructor, taking the XML file URL.
064: * @param storeMgr The StoreManager managing the store that we are auto-starting.
065: * @param clr The ClassLoaderResolver
066: * @throws MalformedURLException
067: */
068: public XMLAutoStarter(StoreManager storeMgr, ClassLoaderResolver clr)
069: throws MalformedURLException {
070: super ();
071:
072: this .fileUrl = new URL("file:"
073: + storeMgr.getOMFContext()
074: .getPersistenceConfiguration()
075: .getAutoStartMechanismXmlFile());
076:
077: final DocumentBuilderFactory factory = DocumentBuilderFactory
078: .newInstance();
079: final DocumentBuilder db;
080:
081: try {
082: db = factory.newDocumentBuilder();
083: try {
084: db
085: .setEntityResolver(new XMLAutoStarterEntityResolver());
086: rootElement = db.parse(
087: new InputSource(new InputStreamReader(fileUrl
088: .openStream()))).getDocumentElement();
089: doc = rootElement.getOwnerDocument();
090: } catch (Exception e) {
091: JPOXLogger.PERSISTENCE.info(LOCALISER.msg("034201",
092: fileUrl.getFile()));
093:
094: // File doesn't exist, so create it
095: doc = db.newDocument();
096: rootElement = doc.createElement("jpox");
097: doc.appendChild(rootElement);
098:
099: writeToFile();
100: }
101: } catch (ParserConfigurationException e1) {
102: JPOXLogger.PERSISTENCE.error(LOCALISER.msg("034202",
103: fileUrl.getFile(), e1.getMessage()));
104: }
105: }
106:
107: /**
108: * Accessor for all auto start data for this starter.
109: * @return The class auto start data. Collection of StoreData elements
110: * @throws DatastoreInitialisationException
111: */
112: public Collection getAllClassData()
113: throws DatastoreInitialisationException {
114: Collection classes = new HashSet();
115:
116: NodeList classElements = rootElement
117: .getElementsByTagName("class");
118: for (int i = 0; i < classElements.getLength(); i++) {
119: Element element = (Element) classElements.item(i);
120:
121: boolean tableBased = true;
122: if (element.getAttribute("table") == null) {
123: tableBased = false;
124: }
125:
126: if (tableBased) {
127: // Default to owner unless specified
128: boolean owner = true;
129: if (element.getAttribute("table-owner") != null
130: && element.getAttribute("table-owner").equals(
131: "false")) {
132: owner = false;
133: }
134:
135: StoreData classData = new TableStoreData(
136: element.getAttribute("name"),
137: element.getAttribute("table"),
138: owner,
139: element.getAttribute("type").equals("FCO") ? TableStoreData.FCO_TYPE
140: : TableStoreData.SCO_TYPE, element
141: .getAttribute("interface-name"));
142: classes.add(classData);
143: } else {
144: StoreData classData = new StoreData(
145: element.getAttribute("name"),
146: null,
147: element.getAttribute("type").equals("FCO") ? TableStoreData.FCO_TYPE
148: : TableStoreData.SCO_TYPE, element
149: .getAttribute("interface-name"));
150: classes.add(classData);
151: }
152: }
153:
154: return classes;
155: }
156:
157: /**
158: * Whether it's open for writing (add/delete) classes to the auto start
159: * mechanism
160: * @return whether this is open for writing
161: */
162: public boolean isOpen() {
163: // Always open
164: return true;
165: }
166:
167: /**
168: * Closes a transaction for writing (add/delete) classes to the auto start
169: * mechanism
170: */
171: public void close() {
172: writeToFile();
173: super .close();
174: }
175:
176: /**
177: * Method to add a class to the starter.
178: * @param data The store data to add
179: */
180: public void addClass(StoreData data) {
181: // TODO Check for existence of this class
182: Element classElement = doc.createElement("class");
183: classElement.setAttribute("name", data.getName());
184: if (data instanceof TableStoreData) {
185: TableStoreData tableData = (TableStoreData) data;
186: if (tableData.hasTable()) {
187: classElement.setAttribute("table", tableData
188: .getTableName());
189: classElement.setAttribute("table-owner", tableData
190: .isTableOwner() ? "true" : "false");
191: }
192: classElement.setAttribute("type", tableData.isFCO() ? "FCO"
193: : "SCO");
194: classElement.setAttribute("version",
195: ObjectManagerFactoryImpl.getVersionNumber());
196: if (tableData.getInterfaceName() != null) {
197: classElement.setAttribute("interface-name", tableData
198: .getInterfaceName());
199: }
200: }
201:
202: rootElement.appendChild(classElement);
203: }
204:
205: /**
206: * Method to remove a class from the starter
207: * @param className The name of the class to remove.
208: */
209: public void deleteClass(String className) {
210: NodeList classElements = rootElement
211: .getElementsByTagName("class");
212: for (int i = 0; i < classElements.getLength(); i++) {
213: Element element = (Element) classElements.item(i);
214: String attr = element.getAttribute("name");
215: if (attr != null && attr.equals(className)) {
216: rootElement.removeChild(element);
217: }
218: }
219: }
220:
221: /**
222: * Method to remove all classes from the starter.
223: */
224: public void deleteAllClasses() {
225: final DocumentBuilderFactory factory = DocumentBuilderFactory
226: .newInstance();
227: final DocumentBuilder db;
228:
229: try {
230: // Dont do any deletion, just reconstruct the DOM with an empty root element
231: db = factory.newDocumentBuilder();
232: doc = db.newDocument();
233: rootElement = doc.createElement("jpox");
234: doc.appendChild(rootElement);
235: } catch (ParserConfigurationException e) {
236: JPOXLogger.PERSISTENCE.error(LOCALISER.msg("034203",
237: fileUrl.getFile(), e.getMessage()));
238: }
239: }
240:
241: /**
242: * Method to give a descriptive name for the starter process.
243: * @return Description of the starter process.
244: */
245: public String getStorageDescription() {
246: return LOCALISER.msg("034200");
247: }
248:
249: /**
250: * Method to write the DOM to its file.
251: */
252: private synchronized void writeToFile() {
253: // Write the DOM back to file
254: try {
255: TransformerFactory tf = TransformerFactory.newInstance();
256: Transformer m = tf.newTransformer();
257: DOMSource source = new DOMSource(doc);
258: FileOutputStream os = new FileOutputStream(fileUrl
259: .getFile());
260: StreamResult result = new StreamResult(os);
261: m.setOutputProperty(OutputKeys.INDENT, "yes");
262: m.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
263: XMLAutoStarterEntityResolver.PUBLIC_ID_KEY);
264: m.transform(source, result);
265: os.close();
266: } catch (Exception e) {
267: e.printStackTrace();
268: JPOXLogger.PERSISTENCE.error(LOCALISER.msg("034203",
269: fileUrl.getFile(), e.getMessage()));
270: }
271: }
272: }
|