blob: 3b15afb882edaa35ce371b17a7c5327842ece3bb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.j2ee.persistence.editor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleElementVisitor6;
import javax.swing.text.Document;
import org.netbeans.api.db.explorer.ConnectionManager;
import org.netbeans.api.db.explorer.DatabaseConnection;
import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.java.source.ClasspathInfo;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.ElementUtilities;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.Task;
import org.netbeans.api.java.source.ui.ElementOpen;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.modules.j2ee.persistence.dd.common.PersistenceUnit;
import org.netbeans.modules.j2ee.persistence.provider.ProviderUtil;
import org.netbeans.modules.j2ee.persistence.spi.datasource.JPADataSource;
import org.netbeans.modules.j2ee.persistence.spi.datasource.JPADataSourceProvider;
import org.openide.ErrorManager;
import org.openide.awt.StatusDisplayer;
import org.openide.filesystems.FileObject;
import org.openide.util.NbBundle;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
*
* @author Dongmei Cao
*/
public class JPAEditorUtil {
public static final String JDBCURLKEY="url";//NOI18N
public static final String JDBCUSERKEY="user";//NOI18N
public static final String JDBCDRIVERKEY="driver";//NOI18N
public static JavaSource getJavaSource(Document doc) {
FileObject fileObject = NbEditorUtilities.getFileObject(doc);
if (fileObject == null) {
return null;
}
Project project = FileOwnerQuery.getOwner(fileObject);
if (project == null) {
return null;
}
// XXX this only works correctly with projects with a single sourcepath,
// but we don't plan to support another kind of projects anyway (what about Maven?).
// mkleint: Maven has just one sourceroot for java sources, the config files are placed under
// different source root though. JavaProjectConstants.SOURCES_TYPE_RESOURCES
SourceGroup[] sourceGroups = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
for (SourceGroup sourceGroup : sourceGroups) {
return JavaSource.create(ClasspathInfo.create(sourceGroup.getRootFolder()));
}
return null;
}
public static Node getClassNode(Node tag) {
if (tag == null) {
return null;
}
if (tag.getNodeName().equalsIgnoreCase("class") || // NOI18N
tag.getNodeName().equalsIgnoreCase("subclass") || // NOI18N
tag.getNodeName().equalsIgnoreCase("joined-subclass") || // NOI18N
tag.getNodeName().equalsIgnoreCase("union-subclass")) { // NOI18N
return tag;
}
Node current = tag;
while (true) {
Node parent = current.getParentNode();
if(parent == null) {
// See issue 138974
return null;
}
if (parent.getNodeName().equalsIgnoreCase("class") || // NOI18N
parent.getNodeName().equalsIgnoreCase("subclass") || // NOI18N
parent.getNodeName().equalsIgnoreCase("joined-subclass") || // NOI18N
parent.getNodeName().equalsIgnoreCase("union-subclass")) {
// Found it
return parent;
} else if (parent.getNodeName().equalsIgnoreCase("hibernate-mapping")) {
// Hit the root element
return null;
} else {
// Keep going
current = parent;
}
}
}
public static String getClassName(Node tag) {
Node classNode = getClassNode(tag);
if (classNode != null) {
NamedNodeMap attribs = classNode.getAttributes();
if (attribs != null && attribs.getNamedItem("name") != null) { // NOI18N
return attribs.getNamedItem("name").getNodeValue(); // NOI18N
}
}
return null;
}
public static String getTableName(Node tag) {
Node classNode = getClassNode(tag);
if (classNode != null) {
NamedNodeMap attribs = classNode.getAttributes();
if (attribs != null && attribs.getNamedItem("table") != null) { // NOI18N
return attribs.getNamedItem("table").getNodeValue(); // NOI18N
}
}
return null;
}
public static String getPersistencePropertyName(Node tag) {
if (!tag.getNodeName().equalsIgnoreCase("property")) {
return null;
} else {
NamedNodeMap attribs = tag.getAttributes();
if (attribs != null && attribs.getNamedItem("name") != null) { // NOI18N
return attribs.getNamedItem("name").getNodeValue();
}
}
return null;
}
public static TypeElement findClassElementByBinaryName(final String binaryName, CompilationController cc) {
if (!binaryName.contains("$")) { // NOI18N
// fast search based on fqn
return cc.getElements().getTypeElement(binaryName);
} else {
// get containing package
String packageName = ""; // NOI18N
int dotIndex = binaryName.lastIndexOf("."); // NOI18N
if (dotIndex != -1) {
packageName = binaryName.substring(0, dotIndex);
}
PackageElement packElem = cc.getElements().getPackageElement(packageName);
if (packElem == null) {
return null;
}
// scan for element matching the binaryName
return new BinaryNameTypeScanner().visit(packElem, binaryName);
}
}
private static class BinaryNameTypeScanner extends SimpleElementVisitor6<TypeElement, String> {
@Override
public TypeElement visitPackage(PackageElement packElem, String binaryName) {
for (Element e : packElem.getEnclosedElements()) {
if (e.getKind().isClass()) {
TypeElement ret = e.accept(this, binaryName);
if (ret != null) {
return ret;
}
}
}
return null;
}
}
public static void findAndOpenJavaClass(final String classBinaryName, Document doc) {
final JavaSource js = getJavaSource(doc);
if (js != null) {
try {
js.runUserActionTask(new Task<CompilationController>() {
public void run(CompilationController cc) throws Exception {
boolean opened = false;
TypeElement element = findClassElementByBinaryName(classBinaryName, cc);
if (element != null) {
opened = ElementOpen.open(js.getClasspathInfo(), element);
}
if (!opened) {
String msg = NbBundle.getMessage(JPAEditorUtil.class, "LBL_SourceNotFound", classBinaryName);
StatusDisplayer.getDefault().setStatusText(msg);
}
}
}, false);
} catch (IOException ex) {
Logger.getLogger("global").log(Level.SEVERE, ex.getMessage(), ex);
}
}
}
public static VariableElement findFieldElementOnType(ElementUtilities eu, TypeMirror type, String fieldName) {
FieldAcceptor fieldAcceptor = new FieldAcceptor(fieldName);
Iterable<? extends Element> matchingProp = eu.getMembers(type, fieldAcceptor);
Iterator<? extends Element> it = matchingProp.iterator();
// no matching element found
if (!it.hasNext()) {
return null;
} else
return (VariableElement)it.next();
}
private static class FieldAcceptor implements ElementUtilities.ElementAcceptor {
private String fieldName;
public FieldAcceptor(String fieldName) {
this.fieldName = fieldName;
}
public boolean accept(Element e, TypeMirror type) {
if (e.getKind() != ElementKind.FIELD) {
return false;
} else {
if( e.getSimpleName().toString().equals(fieldName) ) {
return true;
}
}
return false;
}
}
public static DatabaseConnection findDatabaseConnection(PersistenceUnit pu, Project project) {
// try to find a connection specified using the PU properties
DatabaseConnection dbcon = ProviderUtil.getConnection(pu);
if (dbcon != null) {
return dbcon;
}
// try to find a datasource-based connection, but only for a FileObject-based context,
// otherwise we don't have a J2eeModuleProvider to retrieve the DS's from
String datasourceName = ProviderUtil.getDatasourceName(pu);
if (datasourceName == null) {
return null;
}
if (project == null) {
return null;
}
JPADataSource datasource = null;
JPADataSourceProvider dsProvider = project.getLookup().lookup(JPADataSourceProvider.class);
if (dsProvider == null) {
return null;
}
for (JPADataSource each : dsProvider.getDataSources()) {
if (datasourceName.equals(each.getJndiName())) {
datasource = each;
}
}
if (datasource == null) {
ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "The " + datasourceName + " was not found."); // NOI18N
return null;
}
List<DatabaseConnection> dbconns = findDatabaseConnections(datasource);
if (dbconns.size() > 0) {
return dbconns.get(0);
}
return null;
}
public static HashMap<String,String> findDatabaseConnectionProperties(PersistenceUnit pu, Project project) {
// try to find a connection specified using the PU properties
HashMap<String,String> props = ProviderUtil.getConnectionProperties(pu);
if (props != null && props.size()>0) {
return props;
}
// try to find a datasource-based connection, but only for a FileObject-based context,
// otherwise we don't have a J2eeModuleProvider to retrieve the DS's from
String datasourceName = ProviderUtil.getDatasourceName(pu);
if (datasourceName == null) {
return null;
}
if (project == null) {
return null;
}
JPADataSource datasource = null;
JPADataSourceProvider dsProvider = project.getLookup().lookup(JPADataSourceProvider.class);
if (dsProvider == null) {
return null;
}
for (JPADataSource each : dsProvider.getDataSources()) {
if (datasourceName.equals(each.getJndiName())) {
datasource = each;
}
}
if (datasource == null) {
ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "The " + datasourceName + " was not found."); // NOI18N
return null;
}
props = new HashMap<String,String>();
props.put(JDBCURLKEY,datasource.getUrl());
props.put(JDBCUSERKEY,datasource.getUsername());
props.put(JDBCDRIVERKEY, datasource.getDriverClassName());
return props;
}
private static List<DatabaseConnection> findDatabaseConnections(JPADataSource datasource) {
// copied from j2ee.common.DatasourceHelper (can't depend on that)
if (datasource == null) {
throw new NullPointerException("The datasource parameter cannot be null."); // NOI18N
}
String databaseUrl = datasource.getUrl();
String user = datasource.getUsername();
if (databaseUrl == null || user == null) {
return Collections.emptyList();
}
List<DatabaseConnection> result = new ArrayList<DatabaseConnection>();
for (DatabaseConnection dbconn : ConnectionManager.getDefault().getConnections()) {
if (databaseUrl.equals(dbconn.getDatabaseURL()) && user.equals(dbconn.getUser())) {
result.add(dbconn);
}
}
if (result.size() > 0) {
return Collections.unmodifiableList(result);
} else {
return Collections.emptyList();
}
}
}