KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > db > explorer > DatabaseConnectionConvertor


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.db.explorer;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.OutputStream JavaDoc;
26 import java.io.OutputStreamWriter JavaDoc;
27 import java.io.PrintWriter JavaDoc;
28 import java.lang.ref.Reference JavaDoc;
29 import java.lang.ref.WeakReference JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.LinkedList JavaDoc;
32 import java.util.Vector JavaDoc;
33 import org.openide.ErrorManager;
34 import org.openide.cookies.InstanceCookie;
35 import org.openide.filesystems.FileLock;
36 import org.openide.filesystems.FileObject;
37 import org.openide.filesystems.FileSystem;
38 import org.openide.filesystems.FileUtil;
39 import org.openide.loaders.Environment;
40 import org.openide.loaders.DataFolder;
41 import org.openide.loaders.DataObject;
42 import org.openide.loaders.MultiDataObject;
43 import org.openide.loaders.XMLDataObject;
44 import org.openide.util.RequestProcessor;
45 import org.openide.util.Lookup;
46 import org.openide.util.WeakListeners;
47 import org.openide.util.lookup.AbstractLookup;
48 import org.openide.util.lookup.InstanceContent;
49 import org.openide.xml.EntityCatalog;
50 import org.openide.xml.XMLUtil;
51 import org.openide.filesystems.Repository;
52 import org.netbeans.modules.db.explorer.nodes.RootNode;
53 import org.xml.sax.Attributes JavaDoc;
54 import org.xml.sax.InputSource JavaDoc;
55 import org.xml.sax.SAXException JavaDoc;
56 import org.xml.sax.XMLReader JavaDoc;
57 import org.xml.sax.helpers.DefaultHandler JavaDoc;
58
59 /**
60  * Reads and writes the database connection registration format.
61  *
62  * @author Radko Najman, Andrei Badea
63  */

64 public class DatabaseConnectionConvertor implements Environment.Provider, InstanceCookie.Of {
65     
66     /**
67      * The path where the connections are registered in the SystemFileSystem.
68      */

69     public static final String JavaDoc CONNECTIONS_PATH = "Databases/Connections"; // NOI18N
70

71     /**
72      * The delay by which the write of the changes is postponed.
73      */

74     private static final int DELAY = 2000;
75     
76     private static FileObject newlyCreated = null;
77     private static DatabaseConnection newlyCreatedInstance = null;
78     
79     private XMLDataObject holder = null;
80
81     /**
82      * The lookup provided through Environment.Provider.
83      */

84     private Lookup lookup = null;
85
86     private Reference JavaDoc refConnection = new WeakReference JavaDoc(null);
87     
88     private PCL listener;
89
90     private static DatabaseConnectionConvertor createProvider() {
91         return new DatabaseConnectionConvertor();
92     }
93     
94     private DatabaseConnectionConvertor() {
95     }
96
97     private DatabaseConnectionConvertor(XMLDataObject object) {
98         this.holder = object;
99         InstanceContent cookies = new InstanceContent();
100         cookies.add(this);
101         lookup = new AbstractLookup(cookies);
102     }
103     
104     private DatabaseConnectionConvertor(XMLDataObject object, DatabaseConnection existingInstance) {
105         this(object);
106         refConnection = new WeakReference JavaDoc(existingInstance);
107         attachListener();
108     }
109     
110     // Environment.Provider methods
111

112     public Lookup getEnvironment(DataObject obj) {
113         if (obj.getPrimaryFile() == newlyCreated) {
114             return new DatabaseConnectionConvertor((XMLDataObject)obj, newlyCreatedInstance).getLookup();
115         } else {
116             return new DatabaseConnectionConvertor((XMLDataObject)obj).getLookup();
117         }
118     }
119     
120     // InstanceCookie.Of methods
121

122     public String JavaDoc instanceName() {
123         return holder.getName();
124     }
125     
126     public Class JavaDoc instanceClass() {
127         return DatabaseConnection.class;
128     }
129     
130     public boolean instanceOf(Class JavaDoc type) {
131         return (type.isAssignableFrom(DatabaseConnection.class));
132     }
133
134     public Object JavaDoc instanceCreate() throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
135         synchronized (this) {
136             Object JavaDoc o = refConnection.get();
137             if (o != null)
138                 return o;
139             Handler JavaDoc handler = new Handler JavaDoc();
140             try {
141                 XMLReader JavaDoc reader = XMLUtil.createXMLReader();
142                 InputSource JavaDoc is = new InputSource JavaDoc(holder.getPrimaryFile().getInputStream());
143                 is.setSystemId(holder.getPrimaryFile().getURL().toExternalForm());
144                 reader.setContentHandler(handler);
145                 reader.setErrorHandler(handler);
146                 reader.setEntityResolver(EntityCatalog.getDefault());
147
148                 reader.parse(is);
149             } catch (SAXException JavaDoc ex) {
150                 Exception JavaDoc x = ex.getException();
151                 if (x instanceof java.io.IOException JavaDoc)
152                     throw (IOException JavaDoc)x;
153                 else
154                     throw new java.io.IOException JavaDoc(ex.getMessage());
155             }
156
157             DatabaseConnection inst = createDatabaseConnection(handler);
158             refConnection = new WeakReference JavaDoc(inst);
159             attachListener();
160             return inst;
161         }
162     }
163
164     private void attachListener() {
165         listener = new PCL();
166         DatabaseConnection dbconn = ((DatabaseConnection)refConnection.get());
167         dbconn.addPropertyChangeListener(WeakListeners.propertyChange(listener, dbconn));
168     }
169
170     private static DatabaseConnection createDatabaseConnection(Handler JavaDoc handler) {
171         DatabaseConnection dbconn = new DatabaseConnection(
172                 handler.driverClass,
173                 handler.driverName,
174                 handler.connectionUrl,
175                 handler.schema,
176                 handler.user,
177                 null);
178         return dbconn;
179     }
180
181     /**
182      * Creates the XML file describing the specified database connection.
183      */

184     public static DataObject create(DatabaseConnection dbconn) throws IOException JavaDoc {
185         FileObject fo = Repository.getDefault().getDefaultFileSystem().findResource(CONNECTIONS_PATH);
186         DataFolder df = DataFolder.findFolder(fo);
187
188         AtomicWriter writer = new AtomicWriter(dbconn, df, convertToFileName(dbconn.getName()));
189         df.getPrimaryFile().getFileSystem().runAtomicAction(writer);
190         return writer.holder;
191     }
192     
193     private static String JavaDoc convertToFileName(String JavaDoc databaseURL) {
194         return databaseURL.substring(0, Math.min(32, databaseURL.length())).replaceAll("[^\\p{Alnum}]", "_"); // NOI18N
195
}
196     
197     /**
198      * Moves the existing database connections from the DatabaseOption
199      * used in 4.1 and previous to the SystemFileSystem.
200      */

201     public static void importOldConnections() {
202         Vector JavaDoc dbconns = RootNode.getOption().getConnections();
203         for (Iterator JavaDoc i = dbconns.iterator(); i.hasNext();) {
204             try {
205                 create((DatabaseConnection)i.next());
206             } catch (IOException JavaDoc e) {
207                 ErrorManager.getDefault().notify(e);
208             }
209             i.remove();
210         }
211     }
212     
213     /**
214      * Removes the file describing the specified database connection.
215      */

216     public static void remove(DatabaseConnection dbconn) throws IOException JavaDoc {
217         String JavaDoc name = dbconn.getName();
218         FileObject fo = Repository.getDefault().getDefaultFileSystem().findResource(CONNECTIONS_PATH); //NOI18N
219
DataFolder folder = DataFolder.findFolder(fo);
220         DataObject[] objects = folder.getChildren();
221         
222         for (int i = 0; i < objects.length; i++) {
223             InstanceCookie ic = (InstanceCookie)objects[i].getCookie(InstanceCookie.class);
224             if (ic != null) {
225                 Object JavaDoc obj = null;
226                 try {
227                     obj = ic.instanceCreate();
228                 } catch (ClassNotFoundException JavaDoc e) {
229                     continue;
230                 }
231                 if (obj instanceof DatabaseConnection) {
232                     DatabaseConnection connection = (DatabaseConnection)obj;
233                     if (connection.getName().equals(name)) {
234                         objects[i].delete();
235                         break;
236                     }
237                 }
238             }
239         }
240     }
241     
242     Lookup getLookup() {
243         return lookup;
244     }
245     
246     /**
247      * Atomic writer for writing a changed/new database connection.
248      */

249     private static final class AtomicWriter implements FileSystem.AtomicAction {
250         
251         DatabaseConnection instance;
252         MultiDataObject holder;
253         String JavaDoc fileName;
254         DataFolder parent;
255
256         /**
257          * Constructor for writing to an existing file.
258          */

259         AtomicWriter(DatabaseConnection instance, MultiDataObject holder) {
260             this.instance = instance;
261             this.holder = holder;
262         }
263
264         /**
265          * Constructor for creating a new file.
266          */

267         AtomicWriter(DatabaseConnection instance, DataFolder parent, String JavaDoc fileName) {
268             this.instance = instance;
269             this.fileName = fileName;
270             this.parent = parent;
271         }
272
273         public void run() throws java.io.IOException JavaDoc {
274             FileLock lck;
275             FileObject data;
276
277             if (holder != null) {
278                 data = holder.getPrimaryEntry().getFile();
279                 lck = holder.getPrimaryEntry().takeLock();
280             } else {
281                 FileObject folder = parent.getPrimaryFile();
282                 String JavaDoc fn = FileUtil.findFreeFileName(folder, fileName, "xml"); //NOI18N
283
data = folder.createData(fn, "xml"); //NOI18N
284
lck = data.lock();
285             }
286
287             try {
288                 OutputStream JavaDoc ostm = data.getOutputStream(lck);
289                 PrintWriter JavaDoc writer = new PrintWriter JavaDoc(new OutputStreamWriter JavaDoc(ostm, "UTF8")); //NOI18N
290
write(writer);
291                 writer.flush();
292                 writer.close();
293                 ostm.close();
294             } finally {
295                 lck.releaseLock();
296             }
297
298             if (holder == null) {
299                 // a new DataObject must be created for instance
300
// ensure that the object returned by this DO's InstanceCookie.instanceCreate()
301
// method is the same as instance
302
newlyCreated = data;
303                 newlyCreatedInstance = instance;
304                 holder = (MultiDataObject)DataObject.find(data);
305                 // ensure the Environment.Provider.getEnvironment() is called for the new DataObject
306
holder.getCookie(InstanceCookie.class);
307                 newlyCreated = null;
308                 newlyCreatedInstance = null;
309             }
310         }
311
312         void write(PrintWriter JavaDoc pw) throws IOException JavaDoc {
313             pw.println("<?xml version='1.0'?>"); //NOI18N
314
pw.println("<!DOCTYPE connection PUBLIC '-//NetBeans//DTD Database Connection 1.0//EN' 'http://www.netbeans.org/dtds/connection-1_0.dtd'>"); //NOI18N
315
pw.println("<connection>"); //NOI18N
316
pw.println(" <driver-class value='" + XMLUtil.toAttributeValue(instance.getDriver()) + "'/>"); //NOI18N
317
pw.println(" <driver-name value='" + XMLUtil.toAttributeValue(instance.getDriverName()) + "'/>"); // NOI18N
318
pw.println(" <database-url value='" + XMLUtil.toAttributeValue(instance.getDatabase()) + "'/>"); //NOI18N
319
if (instance.getSchema() != null) {
320                 pw.println(" <schema value='" + XMLUtil.toAttributeValue(instance.getSchema()) + "'/>"); //NOI18N
321
}
322             if (instance.getUser() != null) {
323                 pw.println(" <user value='" + XMLUtil.toAttributeValue(instance.getUser()) + "'/>"); //NOI18N
324
}
325             pw.println("</connection>"); //NOI18N
326
}
327     }
328
329     /**
330      * SAX handler for reading the XML file.
331      */

332     private static final class Handler extends DefaultHandler JavaDoc {
333         
334         private static final String JavaDoc ELEMENT_DRIVER_CLASS = "driver-class"; // NOI18N
335
private static final String JavaDoc ELEMENT_DRIVER_NAME = "driver-name"; // NOI18N
336
private static final String JavaDoc ELEMENT_DATABASE_URL = "database-url"; // NOI18N
337
private static final String JavaDoc ELEMENT_SCHEMA = "schema"; // NOI18N
338
private static final String JavaDoc ELEMENT_USER = "user"; // NOI18N
339
private static final String JavaDoc ATTR_PROPERTY_VALUE = "value"; // NOI18N
340

341         String JavaDoc driverClass;
342         String JavaDoc driverName;
343         String JavaDoc connectionUrl;
344         String JavaDoc schema;
345         String JavaDoc user;
346
347         public void startDocument() throws SAXException JavaDoc {
348         }
349
350         public void endDocument() throws SAXException JavaDoc {
351         }
352
353         public void startElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName, Attributes JavaDoc attrs) throws SAXException JavaDoc {
354             String JavaDoc value = attrs.getValue(ATTR_PROPERTY_VALUE);
355             if (ELEMENT_DRIVER_CLASS.equals(qName)) {
356                 driverClass = value;
357             } else if (ELEMENT_DRIVER_NAME.equals(qName)) {
358                 driverName = value;
359             } else if (ELEMENT_DATABASE_URL.equals(qName)) {
360                 connectionUrl = value;
361             } else if (ELEMENT_SCHEMA.equals(qName)) {
362                 schema = value;
363             } else if (ELEMENT_USER.equals(qName)) {
364                 user = value;
365             }
366         }
367     }
368     
369     private final class PCL implements PropertyChangeListener JavaDoc, Runnable JavaDoc {
370         
371         /**
372          * The list of PropertyChangeEvent that cause the connections to be saved.
373          * Should probably be a set of DatabaseConnection's instead.
374          */

375         LinkedList JavaDoc/*<PropertyChangeEvent>*/ keepAlive = new LinkedList JavaDoc();
376         
377         RequestProcessor.Task saveTask = null;
378         
379         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
380             synchronized (this) {
381                 if (saveTask == null)
382                     saveTask = RequestProcessor.getDefault().create(this);
383                 keepAlive.add(evt);
384             }
385             saveTask.schedule(DELAY);
386         }
387         
388         public void run() {
389             PropertyChangeEvent JavaDoc e;
390
391             synchronized (this) {
392                 e = (PropertyChangeEvent JavaDoc)keepAlive.removeFirst();
393             }
394             DatabaseConnection dbconn = (DatabaseConnection)e.getSource();
395             try {
396                 holder.getPrimaryFile().getFileSystem().runAtomicAction(new AtomicWriter(dbconn, holder));
397             } catch (IOException JavaDoc ex) {
398                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
399             }
400         }
401     }
402 }
403
Popular Tags