/****************************************************************************** * Copyright (c) 2009-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.editor; import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.LinkedHashMap; import javax.xml.xpath.XPathConstants; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.ebmwebsourcing.petals.common.internal.provisional.formeditor.AbstractJbiEditorPersonality; import com.ebmwebsourcing.petals.common.internal.provisional.formeditor.ISharedEdition; import com.ebmwebsourcing.petals.common.internal.provisional.utils.DomUtils; import com.ebmwebsourcing.petals.common.internal.provisional.utils.JbiXmlUtils; import com.ebmwebsourcing.petals.common.internal.provisional.utils.XPathUtils; import com.ebmwebsourcing.petals.services.PetalsServicesPlugin; import com.ebmwebsourcing.petals.services.editor.ServicesLabelProvider; import com.sun.java.xml.ns.jbi.Jbi; /** * The SU personality for the JBI editor. */ public class SuPersonality extends AbstractJbiEditorPersonality { private ILabelProvider statusLineLabelProvider; /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.editor.IServicesFormEditorPersonality * #getStatusLineLabelProvider() */ @Override public ILabelProvider getStatusLineLabelProvider() { if( this.statusLineLabelProvider == null ) this.statusLineLabelProvider = new ServicesLabelProvider(); return this.statusLineLabelProvider; } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.editor.IServicesFormEditorPersonality * #dispose() */ @Override public void dispose() { if( this.statusLineLabelProvider != null ) this.statusLineLabelProvider.dispose(); } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.editor.IServicesFormEditorPersonality * #matchesPersonality(org.eclipse.core.resources.IFile) */ @Override public boolean matchesPersonality(Jbi jbi, IFile jbiXmlFile ) { return jbi.getServices() != null; } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.su.editor.IJbiEditorPersonality * #getTitle() */ @Override public String getTitle() { return "Service Unit"; } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.su.editor.IJbiEditorPersonality * #getTitleImage() */ @Override public Image getTitleImage() { return PetalsServicesPlugin.loadImage( "icons/obj16/service_unit.png" ); } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.services.su.editor.IJbiEditorPersonality * #createControl(org.eclipse.swt.widgets.Composite, com.ebmwebsourcing.petals.services.su.editor.ISharedEdition) */ @Override public void createControl( Composite parent, ISharedEdition ise ) { new SuEditionComposite( parent, ise ); } /* * (non-Javadoc) * @see com.ebmwebsourcing.petals.common.internal.provisional.formeditor.AbstractJbiEditorPersonality * #saveModel(com.sun.java.xml.ns.jbi.Jbi, org.eclipse.core.resources.IFile, org.eclipse.emf.edit.domain.EditingDomain) */ @Override public void saveModel( final Jbi model, final IFile editedFile, EditingDomain domain ) { Document doc = JbiXmlUtils.saveJbiXmlAsDocument( model ); sortNodes( doc, true ); String s = DomUtils.writeDocument( doc ); try { editedFile.setContents( new ByteArrayInputStream( s.getBytes()), true, true, null ); } catch( CoreException e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } } /** * Sorts the nodes. * <p> * This is not very clean, because this plug-in should not be aware * of the CDK. However, a pure EMF approach is not possible. * Customizing the XML save handler is too complicated. This approach works. * </p> * <p> * One way to solve it would be to merge the JBI meta-model with the CDK model. * But that would prevent this tooling from being used with a possible new CDK. * </p> * * @param doc the document */ public static void sortNodes( Document doc, boolean indent ) { // Find all the provides and consumes if( doc == null ) return; NodeList nodes = (NodeList) XPathUtils.evaluateXPathExpression( "//*[local-name()='provides' or local-name()='consumes']", doc.getDocumentElement(), XPathConstants.NODESET ); if( nodes == null ) return; // Sort their children for( int i=0; i<nodes.getLength(); i++ ) { Element elt = (Element) nodes.item( i ); if( "provides".equalsIgnoreCase( DomUtils.getNodeName( elt ))) { LinkedHashMap<String,Element> map = new LinkedHashMap<String,Element>(); map.put( "timeout", null ); map.put( "validate-wsdl", null ); map.put( "forward-security-subject", null ); map.put( "forward-message-properties", null ); map.put( "forward-attachments", null ); map.put( "wsdl", null ); sortChildren( elt, map, indent ); } else { LinkedHashMap<String,Element> map = new LinkedHashMap<String,Element>(); map.put( "timeout", null ); map.put( "operation", null ); map.put( "mep", null ); sortChildren( elt, map, indent ); } } } /** * Sorts the children for a provides or consumes element. * @param elt the provides or consumes element * @param cdkElements the known CDK elements (keys = element names, values = DOM elements, initialized to null) */ private static void sortChildren( Element elt, LinkedHashMap<String,Element> cdkElements, boolean indent ) { ArrayList<Element> componentElements = new ArrayList<Element> (); ArrayList<Element> unknownCdkElements = new ArrayList<Element> (); // Sort children and remove them progressively for( int i=0; i<elt.getChildNodes().getLength(); i++ ) { Node node = elt.getChildNodes().item( i ); if( !( node instanceof Element )) continue; Element childElt = (Element) node; String ns = childElt.getNamespaceURI(); String name = DomUtils.getNodeName( childElt ); // Component elements: preserve the original order if( ! ns.toLowerCase().contains( "components/extensions" )) { componentElements.add( childElt ); } // CDK elements: store it and update the insertion list later else if( cdkElements.containsKey( name )) cdkElements.put( name, childElt ); else unknownCdkElements.add( childElt ); } // Remove all the children while( elt.getChildNodes().getLength() > 0 ) elt.removeChild( elt.getChildNodes().item( 0 )); // Update the document with the right insertion order // Add some comments too String indentation = indent ? "\t\t\t" : "\t"; elt.appendChild( elt.getOwnerDocument().createTextNode( "\n\n" + indentation )); elt.appendChild( elt.getOwnerDocument().createComment( "CDK Properties" )); elt.appendChild( elt.getOwnerDocument().createTextNode( "\n" + indentation )); for( Element e : cdkElements.values()) { if( e != null ) elt.appendChild( e ); } for( Element e : unknownCdkElements ) { elt.appendChild( e ); } elt.appendChild( elt.getOwnerDocument().createTextNode( "\n\n" + indentation )); elt.appendChild( elt.getOwnerDocument().createComment( "Component's Specific Properties" )); elt.appendChild( elt.getOwnerDocument().createTextNode( "\n" + indentation )); for( Element e : componentElements ) { elt.appendChild( e ); } } }