001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: *//*
041: * DataSourceResolver.java
042: *
043: * Created on September 6, 2006, 10:14 PM
044: *
045: * To change this template, choose Tools | Template Manager
046: * and open the template in the editor.
047: */
048:
049: package org.netbeans.modules.visualweb.dataconnectivity.datasource;
050:
051: import java.io.IOException;
052: import org.netbeans.modules.visualweb.api.j2ee.common.RequestedJdbcResource;
053: import org.netbeans.modules.visualweb.dataconnectivity.model.DataSourceInfo;
054: import org.netbeans.modules.visualweb.dataconnectivity.model.DataSourceInfoListener;
055: import org.netbeans.modules.visualweb.dataconnectivity.model.ProjectDataSourceManager;
056: import org.netbeans.modules.visualweb.project.jsf.services.DesignTimeDataSourceService;
057: import java.util.Iterator;
058: import java.util.List;
059: import java.util.Set;
060: import java.util.logging.Logger;
061: import javax.naming.NamingException;
062: import javax.swing.SwingUtilities;
063: import org.netbeans.api.db.explorer.JDBCDriver;
064: import org.netbeans.api.db.explorer.JDBCDriverManager;
065: import org.netbeans.api.progress.ProgressHandle;
066: import org.netbeans.api.progress.ProgressHandleFactory;
067: import org.netbeans.api.project.Project;
068: import org.netbeans.modules.visualweb.dataconnectivity.model.ProjectDataSourceManager;
069: import org.netbeans.modules.visualweb.dataconnectivity.naming.DatabaseSettingsImporter;
070: import org.netbeans.modules.visualweb.dataconnectivity.project.datasource.ProjectDataSourceTracker;
071: import org.netbeans.modules.visualweb.dataconnectivity.sql.DesignTimeDataSourceHelper;
072: import org.netbeans.modules.visualweb.dataconnectivity.ui.DataSourceCreationNotSupported;
073: import org.netbeans.modules.visualweb.dataconnectivity.utils.ImportDataSource;
074: import org.netbeans.modules.visualweb.insync.Model;
075: import org.netbeans.modules.visualweb.insync.ModelSet;
076: import org.netbeans.modules.visualweb.insync.ModelSetsListener;
077: import org.netbeans.modules.visualweb.insync.models.FacesModelSet;
078: import org.openide.DialogDisplayer;
079: import org.openide.NotifyDescriptor;
080: import org.openide.util.Lookup;
081: import org.openide.util.NbBundle;
082: import org.openide.util.RequestProcessor;
083: import org.openide.util.Utilities;
084: import org.openide.windows.TopComponent;
085:
086: /**
087: *
088: * @author John Baker
089: */
090: public class DataSourceResolver implements DataSourceInfoListener,
091: Runnable {
092: private static final String DRIVER_CLASS_NET = "org.apache.derby.jdbc.ClientDriver"; // NOI18N
093: private static final String DATASOURCE_PREFIX = "java:comp/env/"; // NOI18N
094: private static DataSourceResolver dataSourceResolver;
095: private String dataSourceInfo = null;
096: protected WaitForModelingListener modelingListener = new WaitForModelingListener();
097: private Project project;
098: private ProgressHandle handle = null;
099: private TopComponent topComponent;
100: private RequestProcessor.Task task = null;
101: private final RequestProcessor WAIT_FOR_MODELING_RP = new RequestProcessor(
102: "DataSourceResolver.WAIT_FOR_MODELING_RP"); //NOI18N
103: private Model[] modelSets = null;
104:
105: /** Creates a new instance of DataSourceResolver */
106: private DataSourceResolver() {
107: }
108:
109: public static DataSourceResolver getInstance() {
110: if (dataSourceResolver == null) {
111: dataSourceResolver = new DataSourceResolver();
112: }
113: return dataSourceResolver;
114: }
115:
116: public void dataSourceInfoModified(
117: org.netbeans.modules.visualweb.dataconnectivity.model.DataSourceInfoEvent modelEvent) {
118: dataSourceInfo = modelEvent.getDataSourceInfoId();
119: }
120:
121: public void datasourceInfoAdded(
122: org.netbeans.modules.visualweb.dataconnectivity.model.DataSourceInfoEvent modelEvent) {
123: dataSourceInfo = modelEvent.getDataSourceInfoId();
124: }
125:
126: public void dataSourceInfoRemoved(
127: org.netbeans.modules.visualweb.dataconnectivity.model.DataSourceInfoEvent modelEvent) {
128: ; // no-op
129: }
130:
131: // if a project data source does not have a corresponding connetion then return true
132: public boolean isDataSourceMissing(Project project, String prjDsName) {
133: DesignTimeDataSourceService dataSourceService = Lookup
134: .getDefault().lookup(DesignTimeDataSourceService.class);
135: Set<RequestedJdbcResource> problemDatasources = dataSourceService
136: .getBrokenDatasources(project);
137:
138: boolean missing = false;
139: Iterator it = problemDatasources.iterator();
140: while (it.hasNext()) {
141: RequestedJdbcResource reqRes = (RequestedJdbcResource) it
142: .next();
143: if (("jdbc/" + prjDsName).equals(reqRes.getJndiName())) { //NOI18N
144: missing = true;
145: break; // data source match made, stop checking
146: }
147: }
148:
149: return missing;
150: }
151:
152: public Set<RequestedJdbcResource> getProjectDataSources(
153: Project project) {
154: DesignTimeDataSourceService dataSourceService = Lookup
155: .getDefault().lookup(DesignTimeDataSourceService.class);
156: return dataSourceService.getProjectDataSources(project);
157: }
158:
159: public boolean isDataSourceUnique(Project currentProj,
160: String dsName, String url) {
161: String[] dynamicDataSources = ProjectDataSourceTracker
162: .getDynamicDataSources(currentProj);
163:
164: for (String name : dynamicDataSources) {
165: if (name.equals((DATASOURCE_PREFIX + "/jdbc/" + dsName))) { // NOI18N
166: if (!getDataSourceUrl(dsName).equals(url)) {
167: return false;
168: }
169: }
170: }
171:
172: return true;
173: }
174:
175: private String getDataSourceUrl(String dsName) {
176: String url = null;
177: DataSourceInfo dsInfo = null;
178:
179: List<DataSourceInfo> dataSourcesInfo = DatabaseSettingsImporter
180: .getInstance().getDataSourcesInfo();
181: Iterator it = dataSourcesInfo.iterator();
182: while (it.hasNext()) {
183: dsInfo = (DataSourceInfo) it.next();
184: if (dsName.equals(dsInfo.getName())) {
185: url = dsInfo.getUrl();
186: }
187: }
188:
189: return url;
190: }
191:
192: public void updateSettings() {
193: doCopying();
194: registerConnections();
195: }
196:
197: public void update(Project currentProj) {
198: updateProject(currentProj);
199: }
200:
201: // Find a matching driver registered with the IDE
202: public JDBCDriver findMatchingDriver(String driverClass) {
203: int i = 0;
204: JDBCDriver[] newDrivers;
205: newDrivers = JDBCDriverManager.getDefault().getDrivers();
206:
207: for (i = 0; i < newDrivers.length; i++) {
208: if (newDrivers[i].getClassName().equals(driverClass)) {
209: return newDrivers[i];
210: } else if (driverClass.equals("org.gjt.mm.mysql.Driver")) { // NOI18N
211: if (newDrivers[i].getClassName().equals(
212: "com.mysql.jdbc.Driver")) { // NOI18N
213: return newDrivers[i];
214: }
215: }
216: }
217:
218: return null;
219: }
220:
221: private boolean updateProject(Project project, DataSourceInfo dsInfo) {
222: boolean needAdd = false;
223: ProjectDataSourceManager projectDataSourceManager = new ProjectDataSourceManager(
224: project);
225:
226: // if project's datasource hasn't been added, then add it
227: if (projectDataSourceManager.getDataSourceWithName(dsInfo
228: .getName()) == null) {
229: projectDataSourceManager.addDataSource(dsInfo);
230: needAdd = true;
231: } else {
232: needAdd = false;
233: }
234: return needAdd;
235: }
236:
237: private void doCopying() {
238: try {
239: ImportDataSource.prepareCopy();
240: } catch (IOException ioe) {
241: Logger.getLogger("copy").info(
242: "Migrating user settings failed " + ioe); //NOI18N
243: }
244: }
245:
246: private void registerConnections() {
247: JDBCDriver[] drvsArray = JDBCDriverManager.getDefault()
248: .getDrivers(DRIVER_CLASS_NET);
249: if (drvsArray.length > 0) {
250: DatabaseSettingsImporter.getInstance()
251: .locateAndRegisterDrivers();
252: DatabaseSettingsImporter.getInstance()
253: .locateAndRegisterConnections(false);
254: }
255: }
256:
257: private void updateProject(Project project) {
258: // Update Project's datasources
259: try {
260: new DesignTimeDataSourceHelper().updateDataSource(project);
261: checkConnections(project);
262: } catch (NamingException ne) {
263: Logger.getLogger("copy").info(
264: "Migrating user settings failed " + ne); //NOI18N
265: }
266: }
267:
268: // Check if any database connections needed by the project are missing
269: private void checkConnections(Project project) {
270: DesignTimeDataSourceService dataSourceService = Lookup
271: .getDefault().lookup(DesignTimeDataSourceService.class);
272: Set<RequestedJdbcResource> problemDatasources = dataSourceService
273: .getBrokenDatasources(project);
274: if (!problemDatasources.isEmpty()) {
275: ImportDataSource.showAlert();
276: }
277: }
278:
279: /**
280: * Post an information dialog to inform the user that the target application server does not support the automatic creation of data sources
281: */
282: public synchronized void postUnsupportedDataSourceCreationDialog() {
283: SwingUtilities.invokeLater(new Runnable() {
284: public void run() {
285: DataSourceCreationNotSupported noDataSourceDialog = new DataSourceCreationNotSupported();
286: NotifyDescriptor nd = new NotifyDescriptor.Message(
287: NbBundle.getMessage(
288: DataSourceCreationNotSupported.class,
289: "MSG_DataSourceNotSupported"),
290: NotifyDescriptor.WARNING_MESSAGE); //NOI18N
291: DialogDisplayer.getDefault().notify(nd);
292: noDataSourceDialog.setVisible(true);
293: }
294: });
295: }
296:
297: public void modelProjectForDataSources(Project currentProj) {
298: project = currentProj;
299: ModelSet.addModelSetsListener(modelingListener);
300: topComponent = TopComponent.getRegistry().getActivated();
301: topComponent.setCursor(Utilities
302: .createProgressCursor(topComponent));
303: String progressBarLabel = org.openide.util.NbBundle.getMessage(
304: DataSourceResolver.class, "ProgressBarLabel"); //NOI18N
305:
306: try {
307: // model project
308: FacesModelSet modelSet = FacesModelSet
309: .startModeling(project);
310:
311: if (modelSet == null) {
312: handle = ProgressHandleFactory
313: .createHandle(progressBarLabel);
314: handle.start();
315: handle.switchToIndeterminate();
316: }
317:
318: // If modeling has been completed then terminate the progress cursor and update the project
319: if (modelSet != null) {
320: if (handle != null) {
321: handle.finish();
322: }
323:
324: ModelSet.removeModelSetsListener(modelingListener);
325: ProjectDataSourceTracker
326: .refreshDataSourceReferences(project);
327: update(project);
328: }
329: } finally {
330: topComponent.setCursor(null);
331: }
332: }
333:
334: /*
335: * Schedule update task
336: */
337: public synchronized void updateTask() {
338: if (task == null) {
339: task = WAIT_FOR_MODELING_RP.create(this );
340: }
341: task.schedule(50);
342: }
343:
344: /*
345: * Update data sources in the project
346: */
347: public synchronized void run() {
348: // make sure the sources are modeled
349: for (Model mModel : modelSets) {
350: String filenameExt = mModel.getFile().getExt();
351: if (filenameExt.equals("java")) {
352: FacesModelSet
353: .getFacesModelIfAvailable(mModel.getFile());
354: }
355: }
356:
357: // Refresh data sources in a project
358: ProjectDataSourceTracker.refreshDataSourceReferences(project);
359: // Update the resource references in the project
360: update(project);
361:
362: // Terminate the progress cursor when done
363: SwingUtilities.invokeLater(new Runnable() {
364: public void run() {
365: if (handle != null) {
366: handle.finish();
367: }
368: }
369: });
370:
371: // clean up
372: modelSets = null;
373: ModelSet.removeModelSetsListener(modelingListener);
374: }
375:
376: public boolean isDatasourceCreationSupported(Project project) {
377: DesignTimeDataSourceService dataSourceService = Lookup
378: .getDefault().lookup(DesignTimeDataSourceService.class);
379: return dataSourceService.isDatasourceCreationSupported(project);
380: }
381:
382: public class WaitForModelingListener implements ModelSetsListener {
383:
384: /*---------- ModelSetsListener------------*/
385:
386: public void modelSetAdded(ModelSet modelSet) {
387: try {
388: // update data sources, if necessary
389: modelSets = modelSet.getModels();
390: updateTask();
391: } finally {
392: task.waitFinished();
393: topComponent.setCursor(null);
394: }
395: }
396:
397: public void modelSetRemoved(ModelSet modelSet) {
398: // not implemented
399: }
400:
401: public void modelProjectChanged() {
402: // not implemented
403: }
404:
405: /*---------- end of interface implements ------------*/
406: }
407: }
|