/******************************************************************************
* Copyright (c) 2008-2013, Linagora
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Linagora - initial API and implementation
*******************************************************************************/
package com.ebmwebsourcing.petals.services.su.nature;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.eclipse.bpel.common.wsdl.helpers.UriAndUrlHelper;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.ebmwebsourcing.petals.common.generation.Mep;
import com.ebmwebsourcing.petals.common.internal.provisional.builder.JbiXmlBuilder;
import com.ebmwebsourcing.petals.common.internal.provisional.builder.MarkerBean;
import com.ebmwebsourcing.petals.common.internal.provisional.emf.InvalidJbiXmlException;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.DomUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.EmfUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.JbiXmlUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.NamespaceUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.PetalsConstants;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.StringUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.WsdlUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.WsdlUtils.JbiBasicBean;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.XPathUtils;
import com.ebmwebsourcing.petals.services.PetalsServicesPlugin;
import com.ebmwebsourcing.petals.services.su.extensions.ComponentVersionDescription;
import com.ebmwebsourcing.petals.services.su.extensions.ExtensionManager;
import com.ebmwebsourcing.petals.services.su.extensions.ValidationRule;
import com.ebmwebsourcing.petals.services.su.jbiproperties.PetalsSPPropertiesManager;
import com.ebmwebsourcing.petals.services.utils.ConsumeUtils;
import com.sun.java.xml.ns.jbi.Consumes;
import com.sun.java.xml.ns.jbi.Jbi;
import com.sun.java.xml.ns.jbi.Provides;
/**
* An incremental builder to validate jbi.xml files of SU projects.
* <p>
* It also updates project properties when the jbi.xml file is modified.
* </p>
*
* @author Vincent Zurczak - EBM WebSourcing
*/
public class SuBuilder extends JbiXmlBuilder {
/**
* The ID of this builder.
*/
public static final String BUILDER_ID = "com.ebmwebsourcing.petals.tools.eclipse.su.main.suBuilder"; //$NON-NLS-1$
/**
* An operation name which means that no operation was found.
*/
private static final QName INEXISTING_OPERATION = new QName( "http://petals-studio", "there-is-no-operation" );
/**
* Runs a full build.
* @param monitor
* @throws CoreException
*/
@Override
protected void fullBuild( final IProgressMonitor monitor ) throws CoreException {
clean( monitor );
getProject().accept( new SuResourceVisitor( monitor ));
}
/**
* Runs an incremental build.
* @param delta
* @param monitor
* @throws CoreException
*/
@Override
protected void incrementalBuild( IResourceDelta delta, IProgressMonitor monitor)
throws CoreException {
delta.accept( new SuDeltaVisitor( monitor ));
}
/**
* The delta visitor used for the incremental build.
*/
private class SuDeltaVisitor implements IResourceDeltaVisitor {
private final IProgressMonitor monitor;
private boolean jbiXmlValidated = false;
/**
* @param monitor
*/
public SuDeltaVisitor( IProgressMonitor monitor ) {
this.monitor = monitor;
}
/*
* (non-Javadoc)
* @see org.eclipse.core.resources.IResourceDeltaVisitor
* #visit(org.eclipse.core.resources.IResourceDelta)
*/
@Override
public boolean visit( IResourceDelta delta ) throws CoreException {
// Already validated?
boolean visitChildren = false;
if( ! this.jbiXmlValidated ) {
// Check for cancellation.
checkCancel( this.monitor );
// Get the resource.
IResource resource = delta.getResource();
IFile jbiXmlFile = null;
if( resource instanceof IContainer ) {
visitChildren = true;
}
else if( resource instanceof IFile ) {
IFile f = (IFile) resource;
if( "wsdl".equalsIgnoreCase( f.getFileExtension())
|| PetalsSPPropertiesManager.PROPERTIES_FILENAME.equals( f.getName()))
jbiXmlFile = resource.getProject().getFile( PetalsConstants.LOC_JBI_FILE );
else if( resource.getProjectRelativePath().toString().equals( PetalsConstants.LOC_JBI_FILE ))
jbiXmlFile = f;
}
if( jbiXmlFile != null ) {
validateAndMarkJbiXmlFile( jbiXmlFile );
this.jbiXmlValidated = true;
}
}
if( this.monitor != null )
this.monitor.worked( 1 );
// Return true to continue visiting children.
return visitChildren;
}
}
/**
* The resource visitor for the full build.
*/
private class SuResourceVisitor implements IResourceVisitor {
private final IProgressMonitor monitor;
/**
* @param monitor
*/
public SuResourceVisitor(IProgressMonitor monitor) {
this.monitor = monitor;
}
/*
* (non-Javadoc)
* @see org.eclipse.core.resources.IResourceVisitor
* #visit(org.eclipse.core.resources.IResource)
*/
@Override
public boolean visit( IResource resource ) {
// Check for cancellation.
checkCancel( this.monitor );
// Do the job: search a jbi.xml file
boolean visitChildren = false;
if( resource instanceof IContainer ) {
visitChildren = true;
}
else if( resource instanceof IFile
&& "jbi.xml".equals( resource.getName()))
validateAndMarkJbiXmlFile((IFile) resource);
if( this.monitor != null )
this.monitor.worked( 1 );
// Return true to continue visiting children.
return visitChildren;
}
}
/**
* Validates a jbi.xml file.
* @param jbiXmlFile
*/
@Override
protected List<MarkerBean> validate( IFile jbiXmlFile ) {
// This builder can only work if the project has the SU nature
// MM validation
List<MarkerBean> markerBeans = super.validate( jbiXmlFile );
if( MarkerBean.containsCriticalError( markerBeans ))
return markerBeans;
// Check the file position
IFile expectedFile = null;
try {
expectedFile = JbiXmlUtils.getJbiXmlFile( jbiXmlFile.getProject());
} catch( FileNotFoundException e1 ) {
// nothing
}
Jbi jbi = null;
try {
jbi = JbiXmlUtils.getJbiXmlModel( jbiXmlFile );
} catch( InvalidJbiXmlException e ) {
// nothing
}
if( expectedFile == null || ! jbiXmlFile.equals( expectedFile )) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_INFO,
"The jbi.xml file is not placed at one of the expected locations (" + PetalsConstants.LOC_JBI_FILE + ").",
jbi,
jbiXmlFile ));
}
// Step 1: check that the BC and provides / consumes are coherent with the component properties
if( jbi == null || jbi.getServices() == null )
return markerBeans;
boolean hasProvides = jbi.getServices().getProvides() != null && jbi.getServices().getProvides().size() > 0;
boolean hasConsumes = jbi.getServices().getConsumes() != null && jbi.getServices().getConsumes().size() > 0;
Properties projectProperties = PetalsSPPropertiesManager.getProperties( jbiXmlFile.getProject());
String suTypeVersion = projectProperties.getProperty( PetalsSPPropertiesManager.COMPONENT_VERSION, "" );
String componentName = projectProperties.getProperty( PetalsSPPropertiesManager.COMPONENT_NAME, "" );
ComponentVersionDescription componentDesc = ExtensionManager.INSTANCE.findDescriptionByComponentNameAndVersion( componentName, null );
if( componentDesc != null ) {
// General properties of the component
if( jbi.getServices().isBindingComponent() != componentDesc.isBc()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The 'binding-component' attribute does not match the target component type. "
+ componentName + " is a " + (componentDesc.isBc() ? "binding-component." : "service engine." ),
jbi.getServices(),
jbiXmlFile ));
}
// Version properties
String searchedVersion = "petals-se-eip".equalsIgnoreCase( componentName ) ? null : suTypeVersion;
componentDesc = ExtensionManager.INSTANCE.findDescriptionByComponentNameAndVersion( componentName, searchedVersion );
if( componentDesc == null
&& suTypeVersion != null
&& suTypeVersion.toLowerCase().endsWith( "-snapshot" )) {
String newV = suTypeVersion.substring( 0, suTypeVersion.length() - 9 );
componentDesc = ExtensionManager.INSTANCE.findDescriptionByComponentNameAndVersion( componentName, newV );
if( componentDesc != null )
suTypeVersion = newV;
}
if( componentDesc != null ) {
if( hasProvides
&& ! componentDesc.isProvide()
&& ! componentDesc.isProxy()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The target component (" + componentName + ") does not allow 'provides' sections.",
jbi.getServices(),
jbiXmlFile ));
}
if( hasConsumes
&& ! componentDesc.isConsume()
&& ! componentDesc.isProxy()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The target component (" + componentName + ") does not allow 'consumes' sections." ,
jbi.getServices(),
jbiXmlFile ));
}
} else {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_WARNING,
"Validation is incomplete: the component " + componentName + " " + suTypeVersion + " is not known by the tooling." ,
jbi.getServices(),
jbiXmlFile ));
}
} else {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_WARNING,
"Validation is incomplete: the component " + componentName + " is not known by the tooling." ,
jbi.getServices(),
jbiXmlFile ));
}
if( MarkerBean.containsCriticalError( markerBeans ))
return markerBeans;
// Step 2: check that there is a coherent MEP and an operation attributes...
// The SOAP component is not concerned by this verification.
if( hasConsumes
&& ! "petals-bc-soap".equalsIgnoreCase( componentName )) {
// Due to what looks like a bug or a limitation in EMF,
// we have to use DOM...
// Parsing is done only once for all the consumes...
File f = EmfUtils.getUnderlyingFile( jbi );
Map<Consumes,QName> consumesToOperation;
if( f != null ) {
consumesToOperation = findConsumesToOperation( f, jbi.getServices().getConsumes());
} else {
consumesToOperation = Collections.emptyMap();
PetalsServicesPlugin.log( "Cannot validate the operations to invoke.", IStatus.INFO );
}
for( Map.Entry<Consumes,QName> entry : consumesToOperation.entrySet()) {
// MEP
Consumes consumes = entry.getKey();
String mepValue = JbiXmlUtils.getMepValue( consumes );
if( mepValue == null ) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_WARNING,
"The Message Exchange Pattern( MEP) is not set.",
EmfUtils.getXpathExpression( consumes ) + "/*[local-name()='mep']",
jbiXmlFile ));
}
// Operation
QName opValue = entry.getValue();
if( opValue == null ) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_WARNING,
"The operation to invoke is not a valid qualified name (maybe unbounded prefix).",
EmfUtils.getXpathExpression( consumes ) + "/*[local-name()='operation']",
jbiXmlFile ));
} else if( INEXISTING_OPERATION.equals( opValue )) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_WARNING,
"The operation to invoke is undefined.",
consumes,
jbiXmlFile ));
}
// Find a WSDL that describes this...
else {
Map<QName,Mep> consumableOps = ConsumeUtils.getValidOperationsForConsume(
consumes.getInterfaceName(),
consumes.getServiceName(),
consumes.getEndpointName());
if( consumableOps.isEmpty()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_WARNING,
"No invocable operation was found for this service.",
EmfUtils.getXpathExpression( consumes ) + "/*[local-name()='operation']",
jbiXmlFile ));
} else if( ! consumableOps.containsKey( opValue )) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The invoked operation does not exist for this service.",
EmfUtils.getXpathExpression( consumes ) + "/*[local-name()='operation']",
jbiXmlFile ));
} else {
Mep mep = Mep.whichMep( mepValue );
if( mep != Mep.UNKNOWN
&& consumableOps.get( opValue ) != mep ) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The invocation MEP does not match the operation's one or there is an ambiguity in the service consumption.",
EmfUtils.getXpathExpression( consumes ) + "/*[local-name()='mep']",
jbiXmlFile ));
}
}
}
}
}
// Step 2-bis (for provides): check that there is a WSDL attribute...
// ... and that its values points to an existing file
if( hasProvides ) {
Map<Provides,URI> providesToWsdlUri = new HashMap<Provides,URI> ();
for( Provides provides : jbi.getServices().getProvides()) {
String wsdlValue = JbiXmlUtils.getWsdlValue( provides );
// No given WSDL
if( StringUtils.isEmpty( wsdlValue )) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_WARNING,
"The provides section does not declare a WSDL file.",
provides,
jbiXmlFile ));
// And the itf and srv name spaces must be the same (dixit Roland)
String srvNs;
if( provides.getServiceName() != null
&& provides.getServiceName().getNamespaceURI() != null )
srvNs = provides.getServiceName().getNamespaceURI();
else
srvNs = "";
String itfNs;
if( provides.getInterfaceName() != null
&& provides.getInterfaceName().getNamespaceURI() != null )
itfNs = provides.getInterfaceName().getNamespaceURI();
else
itfNs = "";
if( ! srvNs.equals( itfNs )) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"Since there is no declared WSDL, the interface and service name spaces must be the same.",
provides,
jbiXmlFile ));
}
}
// A WSDL is expected - File or URI
else {
File wsdlFile = JbiXmlUtils.getWsdlFile( jbiXmlFile, wsdlValue );
if( wsdlFile == null ) {
try {
URI wsdlUri = UriAndUrlHelper.urlToUri( wsdlValue );
providesToWsdlUri.put( provides, wsdlUri );
} catch( Exception e ) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The WSDL location is not a valid URI.",
EmfUtils.getXpathExpression( provides ) + "/*[local-name()='wsdl']",
jbiXmlFile ));
}
} else if( ! wsdlFile.exists()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The referenced WSDL file does not exist.",
EmfUtils.getXpathExpression( provides ) + "/*[local-name()='wsdl']",
jbiXmlFile ));
}
else {
providesToWsdlUri.put( provides, wsdlFile.toURI());
}
}
}
if( MarkerBean.containsCriticalError( markerBeans ))
return markerBeans;
// Step 3: check that the jbi.xml values and the WSDL properties are coherent
for( Map.Entry<Provides,URI> entry : providesToWsdlUri.entrySet()) {
try {
Provides p = entry.getKey();
List<JbiBasicBean> beans = null;
try {
beans = WsdlUtils.INSTANCE.parse( entry.getValue());
} catch( InvocationTargetException e ) {
// nothing
}
if( beans == null ) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The WSDL associated with the service " + p.getServiceName().getLocalPart() + " is invalid.",
EmfUtils.getXpathExpression( p ) + "/*[local-name()='wsdl']",
jbiXmlFile ));
continue;
}
if( beans.isEmpty()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_WARNING,
"The WSDL associated with the service " + p.getServiceName().getLocalPart() + " does not seem to contain any data. It may be invalid.",
EmfUtils.getXpathExpression( p ) + "/*[local-name()='wsdl']",
jbiXmlFile ));
continue;
}
// Find interface name first
List<JbiBasicBean> filteredBeans = new ArrayList<JbiBasicBean> ();
for( JbiBasicBean bean : beans ) {
if( ! bean.isPortTypeExists()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The service's binding references an undefined port type.",
EmfUtils.getXpathExpression( p ) + "/*[local-name()='wsdl']",
jbiXmlFile ));
}
if( bean.getInterfaceName().equals( p.getInterfaceName()))
filteredBeans.add( bean );
}
if( filteredBeans.isEmpty()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The interface name " + p.getInterfaceName().getLocalPart() + " defined in the jbi.xml does not match the declared WSDL.",
EmfUtils.getXpathExpression( p ) + "/@interface-name",
jbiXmlFile ));
return markerBeans;
}
// Find services then
beans.clear();
for( JbiBasicBean bean : filteredBeans ) {
if( bean.getServiceName().equals( p.getServiceName()))
beans.add( bean );
}
if( beans.isEmpty()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The service " + p.getServiceName().getLocalPart() + " defined in the jbi.xml was not found in the declared WSDL.",
EmfUtils.getXpathExpression( p ) + "/@service-name",
jbiXmlFile ));
return markerBeans;
}
// Find the end-point name then
filteredBeans.clear();
for( JbiBasicBean bean : beans ) {
if( bean.getEndpointName().equals( p.getEndpointName())) {
filteredBeans.add( bean );
}
}
if( filteredBeans.isEmpty()) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_ERROR,
"The end-point name " + p.getEndpointName() + " defined in the jbi.xml does not match the declared WSDL.",
EmfUtils.getXpathExpression( p ) + "/@endpoint-name",
jbiXmlFile ));
} else if( filteredBeans.size() != 1 ) {
markerBeans.add( new MarkerBean(
IMarker.SEVERITY_WARNING,
"More than one service was found with these identifiers. The WSDL is probably incorrect.",
EmfUtils.getXpathExpression( p ),
jbiXmlFile ));
}
} catch( IllegalArgumentException e ) {
PetalsServicesPlugin.log( e, IStatus.WARNING );
}
}
}
// Step 4: check specific parameters (as defined in extensions)
// TODO
// Set<ValidationRule> validationRules = ExtensionManager.INSTANCE.;
// for( TreeIterator<EObject> it = jbi.eAllContents(); it.hasNext(); ) {
//
// EObject eo = it.next();
// if( eo.eContainmentFeature() != null ) {
// String name = ExtendedMetaData.INSTANCE.getName( eo.eContainmentFeature());
// String namespace = ExtendedMetaData.INSTANCE.getNamespace( eo.eContainmentFeature());
//
// for( ValidationRule vr : validationRules ) {
// if( vr.hasSameQName( namespace, name )) {
//
// // Get the element value
// String value = null;
// EStructuralFeature esf = eo.eContainingFeature();
//
// // Feature Map entry? => validate it
// if( FeatureMapUtil.isFeatureMap( esf )) {
// Object o = eo.eGet( esf );
// if( o instanceof BasicFeatureMap ) {
//
// // The element exists but has an empty value
// if(((BasicFeatureMap) o).isEmpty()) {
// value = "";
// }
//
// // The element exists and has a value
// // Also, skip XML comments!
// else {
// int size = ((BasicFeatureMap) o).size();
// for( int i=0; i<size; i++ ) {
// Object entry = ((BasicFeatureMap) o).getValue( i );
// if( entry != null
// && ! FeatureMapUtil.isComment(((BasicFeatureMap) o).get( i ))) {
// value = entry.toString().trim();
// break;
// }
// }
//
// if( value == null )
// value = "";
// }
// }
//
// MarkerBean markerBean = validateExtendedRule( value, eo, vr, jbiXmlFile );
// if( markerBean != null )
// markerBeans.add( markerBean );
// }
//
// // Otherwise, log a trace to indicate we could not get the element's value
// else {
// PetalsServicesPlugin.log( "The EObject for {" + namespace + "}" + name + " coult not be resolved." , IStatus.WARNING );
// }
// }
// }
// }
// }
return markerBeans;
}
/**
* Checks an extended validation rule.
* @param value the element value
* @param eo an EObject
* @param vr a validation rule
* @param jbiXmlFile the jbi.xml file
* @return a marker bean if an error was found, null otherwise
*/
private MarkerBean validateExtendedRule(
String value,
EObject eo,
ValidationRule vr,
IFile jbiXmlFile ) {
MarkerBean markerBean = null;
// Test a null value
if( value == null ) {
if( ! vr.isNullAccepted()) {
String name = ExtendedMetaData.INSTANCE.getName( eo.eContainmentFeature());
markerBean = new MarkerBean(
IMarker.SEVERITY_ERROR,
"'" + name + " cannot be null.",
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
}
}
// Test an empty value
else if( value.trim().length() == 0 ) {
if( ! vr.isEmptyValueAccepted()) {
String name = ExtendedMetaData.INSTANCE.getName( eo.eContainmentFeature());
markerBean = new MarkerBean(
IMarker.SEVERITY_ERROR,
"'" + name + "' cannot have an empty value.",
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
}
}
// Otherwise, test according to the rule type
else {
switch( vr.getRuleType()) {
case FILE:
File f = new File( value );
if( f.exists() && f.isAbsolute()) {
markerBean = new MarkerBean(
IMarker.SEVERITY_ERROR,
"Referencing an absolute file is not allowed.",
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
} else {
try {
IFile res = JbiXmlUtils.getResourceFile( jbiXmlFile.getProject(), value );
if( ! res.exists()) {
markerBean = new MarkerBean(
IMarker.SEVERITY_ERROR,
"The resource " + value + " does not exist.",
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
} else if( vr.getFileExtension() != null
&& ! vr.getFileExtension().equalsIgnoreCase( res.getFileExtension())) {
markerBean = new MarkerBean(
IMarker.SEVERITY_ERROR,
"This resource was expected to have the extension ." + vr.getFileExtension(),
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
}
} catch( FileNotFoundException e ) {
markerBean = new MarkerBean(
IMarker.SEVERITY_ERROR,
"The resource " + value + " does not exist.",
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
}
}
break;
case JAVA:
IJavaProject jp = null;
try {
if( jbiXmlFile.getProject().hasNature( JavaCore.NATURE_ID )) {
jp = JavaCore.create( jbiXmlFile.getProject());
}
} catch( CoreException e1 ) {
PetalsServicesPlugin.log( e1, IStatus.WARNING );
}
if( jp == null ) {
markerBean = new MarkerBean(
IMarker.SEVERITY_WARNING,
"The project is not a Java project, this resource cannot be validated.",
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
} else {
try {
IType iType = jp.findType( value );
if (iType == null) {
markerBean = new MarkerBean(
IMarker.SEVERITY_ERROR,
"The class " + value + " was not found in the project's class path.",
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
}
} catch( JavaModelException e ) {
PetalsServicesPlugin.log( e, IStatus.WARNING );
}
}
break;
case XPATH:
XPath xpath = XPathFactory.newInstance().newXPath();
try {
xpath.compile( value );
} catch( Exception e ) {
String cause = e.getCause().getMessage();
cause = cause == null ? "" : " " + cause;
markerBean = new MarkerBean(
IMarker.SEVERITY_ERROR,
"Invalid XPath expression." + cause,
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
}
break;
case URI:
try {
UriAndUrlHelper.urlToUri( value );
} catch( Exception e ) {
markerBean = new MarkerBean(
IMarker.SEVERITY_ERROR,
value + " is not a valid URI.",
EmfUtils.getXpathExpression( eo ),
jbiXmlFile );
}
break;
}
}
return markerBean;
}
/**
* Finds the invoked operation for each consumes block.
* @param jbiXmlFile the jbi.xml file (to parse - again)
* @param consumes the consumes block
* @return an association map
*/
private Map<Consumes,QName> findConsumesToOperation( File jbiXmlFile, Collection<Consumes> consumes ) {
// At the beginning, we were getting the value with EMF.
// All the prefixes are stored in the document root, even those that are declared in sub-elements.
// We used to find the operation in the Feature Map, extract the operation name
// and its prefix, and to resolve the name space URI in the prefix map.
//
// Except that if an element redefines a name space prefix, this won't work!
// Typical example in Petals: EIP, where the operation prefix can be redefined
// in every consume.
// We cannot either serialize the "consumes" mark-up, because EMF
// looses the second name space declaration (this is true if the prefix
// is used in an element's value and false if the prefix is used in a
// structural feature).
Map<Consumes,QName> result = new HashMap<Consumes,QName> ();
Document doc = DomUtils.buildDocument( jbiXmlFile );
if( doc != null ) {
NodeList nodes = (NodeList) XPathUtils.evaluateXPathExpression( "//*[local-name()='consumes']", doc, XPathConstants.NODESET );
for( Consumes cons : consumes ) {
Element opElt = null;
// Get the right consumes and then the operation mark-up
for( int i=0; i<nodes.getLength(); i++ ) {
if( !( nodes.item( i ) instanceof Element ))
continue;
Element elt = (Element) nodes.item( i );
String attr = elt.getAttribute( "interface-name" );
if( attr != null
&& cons.getInterfaceName() != null
&& ! attr.endsWith( cons.getInterfaceName().getLocalPart()))
continue;
attr = elt.getAttribute( "service-name" );
if( attr != null
&& cons.getServiceName() != null
&& ! attr.endsWith( cons.getServiceName().getLocalPart()))
continue;
attr = elt.getAttribute( "endpoint-name" );
if( attr != null
&& cons.getEndpointName() != null
&& ! attr.endsWith( cons.getEndpointName()))
continue;
opElt = (Element) XPathUtils.evaluateXPathExpression( "*[local-name()='operation']", elt, XPathConstants.NODE );
break;
}
QName op = INEXISTING_OPERATION;
if( opElt != null )
op = NamespaceUtils.getQNameElement( opElt );
result.put( cons, op );
}
}
return result;
}
}