blob: 94d55eab637b4f689929b421df4def4da1556c27 [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.completion;
import java.io.IOException;
import java.util.*;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.swing.text.Document;
import org.netbeans.api.db.explorer.ConnectionManager;
import org.netbeans.api.db.explorer.DatabaseConnection;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.ElementHandle;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.Task;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction;
import org.netbeans.modules.j2ee.persistence.api.EntityClassScope;
import org.netbeans.modules.j2ee.persistence.api.metadata.orm.Entity;
import org.netbeans.modules.j2ee.persistence.api.metadata.orm.EntityMappingsMetadata;
import org.netbeans.modules.j2ee.persistence.dd.common.Persistence;
import org.netbeans.modules.j2ee.persistence.editor.CompletionContext;
import org.netbeans.modules.j2ee.persistence.editor.JPAEditorUtil;
import org.netbeans.modules.j2ee.persistence.provider.Provider;
import org.netbeans.modules.j2ee.persistence.provider.ProviderUtil;
import org.netbeans.modules.j2ee.persistence.spi.EntityClassScopeProvider;
import org.netbeans.modules.j2ee.persistence.spi.datasource.JPADataSource;
import org.netbeans.modules.j2ee.persistence.spi.datasource.JPADataSourceProvider;
import org.netbeans.modules.j2ee.persistence.wizard.Util;
import org.openide.filesystems.FileObject;
import org.openide.util.Exceptions;
import org.w3c.dom.Node;
/**
* Various completor for code completing XML tags and attributes in Hibername
* configuration and mapping file
*
* @author Dongmei Cao
*/
public abstract class PUCompletor {
static class JtaDatasourceCompletor extends PUCompletor {
@Override
public List<JPACompletionItem> doCompletion(CompletionContext context) {
List<JPACompletionItem> results = new ArrayList<JPACompletionItem>();
int caretOffset = context.getCaretOffset();
String typedChars = context.getTypedPrefix();
Project project = FileOwnerQuery.getOwner(
NbEditorUtilities.getFileObject(context.getDocument()));
JPADataSourceProvider dsProvider = project.getLookup().lookup(JPADataSourceProvider.class);
if(dsProvider != null){
for (JPADataSource val : dsProvider.getDataSources()) {
if(val.getDisplayName().toLowerCase().startsWith(typedChars.trim().toLowerCase())){
JPACompletionItem item = JPACompletionItem.createAttribValueItem(caretOffset - typedChars.length(),
val.getDisplayName());
results.add(item);
}
}
}
setAnchorOffset(context.getCurrentTokenOffset() + 1);
return results;
}
}
static class ProviderCompletor extends PUCompletor {
@Override
public List<JPACompletionItem> doCompletion(CompletionContext context) {
List<JPACompletionItem> results = new ArrayList<JPACompletionItem>();
int caretOffset = context.getCaretOffset();
String typedChars = context.getTypedPrefix();
HashSet<String> providers = new HashSet<String>();
Project project = FileOwnerQuery.getOwner(
NbEditorUtilities.getFileObject(context.getDocument()));
for(Provider provider: Util.getProviders(project)){
String cl = provider.getProviderClass();
if(cl.toLowerCase().startsWith(typedChars.trim().toLowerCase())){
providers.add(cl);
}
}
for (String cl: providers) {
JPACompletionItem item = JPACompletionItem.createAttribValueItem(caretOffset - typedChars.length(),
cl);
results.add(item);
}
setAnchorOffset(context.getCurrentTokenOffset() + 1);
return results;
}
}
static class ExUnlistedClassesCompletor extends PUCompletor {
@Override
public List<JPACompletionItem> doCompletion(CompletionContext context) {
List<JPACompletionItem> results = new ArrayList<JPACompletionItem>();
int caretOffset = context.getCaretOffset();
String typedChars = context.getTypedPrefix();
for (String val : new String[]{"true", "false"}) {//NOI18N
if(val.toLowerCase().startsWith(typedChars.trim().toLowerCase())){
JPACompletionItem item = JPACompletionItem.createAttribValueItem(caretOffset - typedChars.length(),
val);
results.add(item);
}
}
setAnchorOffset(context.getCurrentTokenOffset() + 1);
return results;
}
}
private int anchorOffset = -1;
public abstract List<JPACompletionItem> doCompletion(CompletionContext context);
protected void setAnchorOffset(int anchorOffset) {
this.anchorOffset = anchorOffset;
}
public int getAnchorOffset() {
return anchorOffset;
}
/**
* A simple completor for general attribute value items
*
* Takes an array of strings, the even elements being the display text of
* the items and the odd ones being the corresponding documentation of the
* items
*
*/
public static class AttributeValueCompletor extends PUCompletor {
private String[] itemTexts;
public AttributeValueCompletor(String[] itemTextAndDocs) {
this.itemTexts = itemTextAndDocs;
}
@Override
public List<JPACompletionItem> doCompletion(CompletionContext context) {
List<JPACompletionItem> results = new ArrayList<JPACompletionItem>();
int caretOffset = context.getCaretOffset();
String typedChars = context.getTypedPrefix();
for (int i = 0; i < itemTexts.length; i += 1) {
if (itemTexts[i].startsWith(typedChars.trim())) {
JPACompletionItem item = JPACompletionItem.createAttribValueItem(caretOffset - typedChars.length(),
itemTexts[i]);
results.add(item);
}
}
setAnchorOffset(context.getCurrentTokenOffset() + 1);
return results;
}
}
/**
* A completor for completing class tag
*/
public static class EntityClassCompletor extends PUCompletor {
@Override
public List<JPACompletionItem> doCompletion(final CompletionContext context) {
final List<JPACompletionItem> results = new ArrayList<JPACompletionItem>();
try {
Document doc = context.getDocument();
final String typedChars = context.getTypedPrefix();
JavaSource js = JPAEditorUtil.getJavaSource(doc);
if (js == null) {
return Collections.emptyList();
}
FileObject fo = NbEditorUtilities.getFileObject(context.getDocument());
doJavaCompletion(fo, js, results, typedChars, context.getCurrentTokenOffset());
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
return results;
}
private void doJavaCompletion(final FileObject fo, final JavaSource js, final List<JPACompletionItem> results,
final String typedPrefix, final int substitutionOffset) throws IOException {
js.runUserActionTask(new Task<CompilationController>() {
@Override
public void run(CompilationController cc) throws Exception {
cc.toPhase(Phase.ELEMENTS_RESOLVED);
Project project = FileOwnerQuery.getOwner(fo);
EntityClassScopeProvider provider = (EntityClassScopeProvider) project.getLookup().lookup(EntityClassScopeProvider.class);
EntityClassScope ecs = null;
Entity[] entities = null;
if (provider != null) {
ecs = provider.findEntityClassScope(fo);
}
if (ecs != null) {
entities = ecs.getEntityMappingsModel(false).runReadAction(new MetadataModelAction<EntityMappingsMetadata, Entity[]>() {
@Override
public Entity[] run(EntityMappingsMetadata metadata) throws Exception {
return metadata.getRoot().getEntity();
}
});
}
// add classes
if(entities != null) {
for (Entity entity : entities) {
if (typedPrefix.length() == 0 || entity.getClass2().toLowerCase().startsWith(typedPrefix.toLowerCase()) || entity.getName().toLowerCase().startsWith(typedPrefix.toLowerCase())) {
JPACompletionItem item = JPACompletionItem.createAttribValueItem(substitutionOffset, entity.getClass2());
results.add(item);
}
}
}
}
}, true);
setAnchorOffset(substitutionOffset);
}
}
/**
* A completor for completing Java properties/fields attributes
*/
public static class PropertyCompletor extends PUCompletor {
public PropertyCompletor() {
}
@Override
public List<JPACompletionItem> doCompletion(final CompletionContext context) {
final List<JPACompletionItem> results = new ArrayList<JPACompletionItem>();
final int caretOffset = context.getCaretOffset();
final String typedChars = context.getTypedPrefix();
final String className = JPAEditorUtil.getClassName(context.getTag());
if (className == null) {
return Collections.emptyList();
}
try {
// Compile the class and find the fiels
JavaSource classJavaSrc = JPAEditorUtil.getJavaSource(context.getDocument());
classJavaSrc.runUserActionTask(new Task<CompilationController>() {
@Override
public void run(CompilationController cc) throws Exception {
cc.toPhase(Phase.ELEMENTS_RESOLVED);
TypeElement typeElem = cc.getElements().getTypeElement(className);
if (typeElem == null) {
return;
}
List<? extends Element> clsChildren = typeElem.getEnclosedElements();
for (Element clsChild : clsChildren) {
if (clsChild.getKind() == ElementKind.FIELD) {
VariableElement elem = (VariableElement) clsChild;
JPACompletionItem item = JPACompletionItem.createClassPropertyItem(caretOffset - typedChars.length(), elem, ElementHandle.create(elem), cc.getElements().isDeprecated(clsChild));
results.add(item);
}
}
}
}, true);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
setAnchorOffset(context.getCurrentTokenOffset() + 1);
return results;
}
}
/**
* A completor for completing the persistence property names in
* persistence.xml file
*
*/
public static class PersistencePropertyNameCompletor extends PUCompletor {
private Map<Provider, Map<String, String[]>> allKeyAndValues;
PersistencePropertyNameCompletor(Map<Provider, Map<String, String[]>> allKeyAndValues) {
this.allKeyAndValues = allKeyAndValues;
}
@Override
public List<JPACompletionItem> doCompletion(CompletionContext context) {
List<JPACompletionItem> results = new ArrayList<JPACompletionItem>();
int caretOffset = context.getCaretOffset();
String typedChars = context.getTypedPrefix();
String providerClass = getProviderClass(context.getTag());
Project enclosingProject = FileOwnerQuery.getOwner(
NbEditorUtilities.getFileObject(context.getDocument()));
Provider provider = ProviderUtil.getProvider(providerClass, enclosingProject);
ArrayList<String> keys = new ArrayList<String>();
String ver = provider == null ? context.getDocumentContext().getVersion() : ProviderUtil.getVersion(provider);
if (provider == null || (ver!=null && !Persistence.VERSION_1_0.equals(ver))) {
keys.addAll(allKeyAndValues.get(null).keySet());
}
if (provider != null && allKeyAndValues.get(provider) != null) {
keys.addAll(allKeyAndValues.get(provider).keySet());
}
String itemTexts[] = keys.toArray(new String[]{});
for (int i = 0; i < itemTexts.length; i++) {
if (itemTexts[i].startsWith(typedChars.trim())
|| itemTexts[i].startsWith("javax.persistence." + typedChars.trim())) { // NOI18N
JPACompletionItem item = JPACompletionItem.createAttribValueItem(caretOffset - typedChars.length(),
itemTexts[i]);
results.add(item);
}
}
setAnchorOffset(context.getCurrentTokenOffset() + 1);
return results;
}
}
/**
* A completor for completing the persistence property value in
* persistence.xml file
*
*/
public static class PersistencePropertyValueCompletor extends PUCompletor {
private Map<Provider, Map<String, String[]>> allKeyAndValues;
PersistencePropertyValueCompletor(Map<Provider, Map<String, String[]>> allKeyAndValues) {
this.allKeyAndValues = allKeyAndValues;
}
@Override
public List<JPACompletionItem> doCompletion(CompletionContext context) {
List<JPACompletionItem> results = new ArrayList<JPACompletionItem>();
int caretOffset = context.getCaretOffset();
String typedChars = context.getTypedPrefix();
String propertyName = getPropertyName(context.getTag());
if (propertyName == null || propertyName.equals("")) {
return results;
}
String providerClass = getProviderClass(context.getTag());
Project enclosingProject = FileOwnerQuery.getOwner(
NbEditorUtilities.getFileObject(context.getDocument()));
Provider provider = ProviderUtil.getProvider(providerClass, enclosingProject);
String[] values = null;
String ver = provider == null ? context.getDocumentContext().getVersion() : ProviderUtil.getVersion(provider);
if (provider == null || (ver!=null && !Persistence.VERSION_1_0.equals(ver))) {
values = allKeyAndValues.get(null).get(propertyName);
}
if (provider != null && allKeyAndValues.get(provider) != null) {
String [] tmp2 = allKeyAndValues.get(provider).get(propertyName);
if(tmp2 != null) {
values = tmp2;
}
if (values == null && propertyName.equals(provider.getJdbcUrl())) {
//always allow this property completion, even for container managed(it's in jta-data-source tag, not in properties)
DatabaseConnection[] cns = ConnectionManager.getDefault().getConnections();
for (DatabaseConnection cn : cns) {
JPACompletionItem item = JPACompletionItem.createAttribValueItem(caretOffset - typedChars.length(),
cn.getDatabaseURL());
results.add(item);
}
results.add(new JPACompletionItem.AddConnectionElementItem());
}
}
if (values != null) {
for (int i = 0; i < values.length; i++) {
JPACompletionItem item = JPACompletionItem.createAttribValueItem(caretOffset - typedChars.length(),
values[i]);
results.add(item);
}
}
setAnchorOffset(context.getCurrentTokenOffset() + 1);
return results;
}
}
/**
* A completor for completing orm mapping files
*/
public static class PersistenceMappingFileCompletor extends PUCompletor {
public PersistenceMappingFileCompletor() {
}
@Override
public List<JPACompletionItem> doCompletion(CompletionContext context) {
List<JPACompletionItem> results = new ArrayList<JPACompletionItem>();
int caretOffset = context.getCaretOffset();
String typedChars = context.getTypedPrefix();
String[] mappingFiles = getMappingFilesFromProject(context);
for (int i = 0; i < mappingFiles.length; i++) {
if (mappingFiles[i].startsWith(typedChars.trim())) {
JPACompletionItem item =
JPACompletionItem.createMappingFileItem(caretOffset - typedChars.length(),
mappingFiles[i]);
results.add(item);
}
}
setAnchorOffset(context.getCurrentTokenOffset() + 1);
return results;
}
// Gets the list of mapping files.
private String[] getMappingFilesFromProject(CompletionContext context) {
Project enclosingProject = FileOwnerQuery.getOwner(
NbEditorUtilities.getFileObject(context.getDocument()));
//use persistence environment when will be supported
if (null != null) {
return null;
} else {
return new String[0];
}
}
}
private static String getProviderClass(Node tag) {
String name = null;
while (tag != null && !"persistence-unit".equals(tag.getNodeName())) {
tag = tag.getParentNode();//NOI18N
}
if (tag != null) {
for (Node ch = tag.getFirstChild(); ch != null; ch = ch.getNextSibling()) {
if ("provider".equals(ch.getNodeName())) {//NOI18N
name = ch.getFirstChild().getNodeValue();
}
}
}
return name;
}
private static String getPropertyName(Node tag) {
String name = null;
while (tag != null && !"property".equals(tag.getNodeName())) {
tag = tag.getParentNode();//NOI18N
}
if (tag != null) {
Node nmN = tag.getAttributes().getNamedItem("name");//NOI18N
if (nmN != null) {
name = nmN.getNodeValue();
}
}
return name;
}
}