blob: c385a7245ac033c9a81f96d6ad6f2c2a0e7b1821 [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.websvc.editor.hints;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;
import java.awt.EventQueue;
import javax.lang.model.element.TypeElement;
import org.netbeans.api.java.source.TreeUtilities;
import org.openide.filesystems.FileObject;
import org.openide.util.WeakListeners;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.java.source.CancellableTask;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.spi.editor.hints.ErrorDescription;
import org.netbeans.spi.editor.hints.HintsController;
import org.netbeans.modules.xml.retriever.catalog.Utilities;
import org.netbeans.modules.xml.wsdl.model.WSDLModel;
import org.netbeans.modules.xml.wsdl.model.WSDLModelFactory;
import org.netbeans.modules.xml.xam.ComponentEvent;
import org.netbeans.modules.xml.xam.ComponentListener;
import org.netbeans.modules.websvc.api.jaxws.project.config.JaxWsModel;
import org.netbeans.modules.websvc.api.jaxws.project.config.Service;
import org.netbeans.modules.websvc.jaxws.api.JAXWSSupport;
import org.netbeans.modules.websvc.editor.hints.common.ProblemContext;
import org.netbeans.modules.websvc.editor.hints.common.RulesEngine;
import org.openide.util.RequestProcessor;
/**
*
* @author Tomasz.Slota@Sun.COM
* @author Ajit.Bhate@Sun.COM
*/
public class WebServicesHintsProvider {
private final static Object singleInstanceLock = new Object();
private static WebServicesHintsProvider runningInstance = null;
private FileObject file;
private boolean cancelled = false;
private ProblemContext context = null;
private List<ErrorDescription> problemsFound = new ArrayList<ErrorDescription>();
private final Object cancellationLock = new Object();
private WSDLModel wsdlModel;
private Service service;
private ComponentListener changeListener;
private static final RequestProcessor WS_HINTS_RP = new RequestProcessor(WebServicesHintsProvider.class);
public WebServicesHintsProvider(FileObject file) {
this.file = file;
}
public void cancel() {
cancelled = true;
synchronized(cancellationLock){
if (context != null){
context.setCancelled(true);
}
}
}
public void run(final CompilationInfo info) throws Exception{
synchronized(singleInstanceLock){
if (runningInstance != null){
runningInstance.cancel();
}
runningInstance = this;
// the 'cancelled' flag must be reset as the instance of WebServicesHintsProvider is reused
cancelled = false;
problemsFound.clear();
for (Tree tree : info.getCompilationUnit().getTypeDecls()){
if (isCancelled()){
break;
}
if (TreeUtilities.CLASS_TREE_KINDS.contains(tree.getKind())){
TreePath path = info.getTrees().getPath(info.getCompilationUnit(), tree);
TypeElement javaClass = (TypeElement) info.getTrees().getElement(path);
if (javaClass != null) {
initServiceMetadata(javaClass);
createProblemContext(info, javaClass);
RulesEngine rulesEngine = new WebServicesRulesEngine();
javaClass.accept(rulesEngine, context);
problemsFound.addAll(rulesEngine.getProblemsFound());
synchronized(cancellationLock){
context = null;
}
}
}
}
//TODO: should we really reset the errors if the task is cancelled?
HintsController.setErrors(file, "WebService Verification", problemsFound); //NOI18N
runningInstance = null;
}
}
private void createProblemContext(CompilationInfo info,
TypeElement javaClass){
context = new ProblemContext();
context.setJavaClass(javaClass);
context.setFileObject(file);
context.setCompilationInfo(info);
if(service!=null) context.addUserObject(service);
if(wsdlModel!=null) context.addUserObject(wsdlModel);
}
private void initServiceMetadata(TypeElement javaClass) {
if (service == null) {
Project owner = FileOwnerQuery.getOwner(file);
if(owner!=null) {
JaxWsModel jaxwsModel = owner.getLookup().lookup(JaxWsModel.class);
if (jaxwsModel != null) {
service = jaxwsModel.findServiceByImplementationClass(javaClass.getQualifiedName().toString());
}
}
}
if (service != null && service.getLocalWsdlFile()!=null) {
JAXWSSupport jaxwsSupport = JAXWSSupport.getJAXWSSupport(file);
if(jaxwsSupport!=null) {
FileObject wsdlFolder = jaxwsSupport.getLocalWsdlFolderForService(service.getName(), false);
if(wsdlFolder!=null) {
FileObject wsdlFo = wsdlFolder.getFileObject(service.getLocalWsdlFile());
if ( wsdlFo == null ){
return;
}
WSDLModel tmpModel = WSDLModelFactory.getDefault().getModel(
Utilities.getModelSource(wsdlFo, true));
if(tmpModel!=wsdlModel) {
if(wsdlModel!=null) {
if(changeListener!=null) {
wsdlModel.removeComponentListener(changeListener);
changeListener = null;
}
}
wsdlModel = tmpModel;
if(wsdlModel!=null) {
if(changeListener==null)
changeListener = WeakListeners.create(ComponentListener.class,
new WsdlModelListener(file), wsdlModel);
wsdlModel.addComponentListener(changeListener);
}
}
}
}
}
}
public boolean isCancelled(){
return cancelled;
}
public List<? extends ErrorDescription> getProblemsFound(){
return problemsFound;
}
public static class ProblemFinderCompInfo extends WebServicesHintsProvider implements CancellableTask<CompilationInfo>{
public ProblemFinderCompInfo(FileObject file){
super(file);
}
}
public static class ProblemFinderCompControl extends WebServicesHintsProvider implements CancellableTask<CompilationController>{
public ProblemFinderCompControl(FileObject file){
super(file);
}
public void run(CompilationController controller) throws Exception {
controller.toPhase(JavaSource.Phase.RESOLVED);
super.run(controller);
}
}
private abstract class RescanTrigger implements Runnable {
private FileObject file;
private JavaSource javaSrc;
private final RequestProcessor.Task wsHintsTask = WS_HINTS_RP.create(this);
RescanTrigger(FileObject file){
this.file = file;
}
void rescan(){
if (javaSrc == null) {
javaSrc = JavaSource.forFileObject(file);
}
if (javaSrc != null){
try{
if(EventQueue.isDispatchThread()) {
wsHintsTask.schedule(100);
} else {
javaSrc.runUserActionTask(new ProblemFinderCompControl(file), true);
}
} catch (IOException e){
}
}
}
@Override
public void run() {
try {
javaSrc.runUserActionTask(new ProblemFinderCompControl(file), true);
} catch (IOException e){}
}
}
private class WsdlModelListener extends RescanTrigger implements ComponentListener {
WsdlModelListener(FileObject file){
super(file);
}
public void valueChanged(ComponentEvent evt) {
if(!WebServicesHintsProvider.this.isCancelled()) {
rescan();
}
}
public void childrenAdded(ComponentEvent evt) {
if(!WebServicesHintsProvider.this.isCancelled()) {
rescan();
}
}
public void childrenDeleted(ComponentEvent evt) {
if(!WebServicesHintsProvider.this.isCancelled()) {
rescan();
}
}
}
}