/* * JBoss, Home of Professional Open Source * Copyright 2012, Red Hat Middleware LLC, and others contributors as indicated * by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.savara.scenario.internal.protocol; import java.util.Set; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.namespace.QName; import org.savara.common.logging.FeedbackHandler; import org.savara.common.model.annotation.Annotation; import org.savara.common.model.annotation.AnnotationDefinitions; import org.savara.common.resources.ResourceLocator; import org.savara.common.util.XMLUtils; import org.savara.protocol.model.util.TypeSystem; import org.savara.scenario.model.Event; import org.savara.scenario.model.Group; import org.savara.scenario.model.Import; import org.savara.scenario.model.Link; import org.savara.scenario.model.MessageEvent; import org.savara.scenario.model.Parameter; import org.savara.scenario.model.ReceiveEvent; import org.savara.scenario.model.Role; import org.savara.scenario.model.Scenario; import org.savara.scenario.model.SendEvent; import org.savara.scenario.model.TimeElapsedEvent; import org.savara.scenario.protocol.ProtocolModelGenerator; import org.scribble.protocol.model.Block; import org.scribble.protocol.model.DataType; import org.scribble.protocol.model.Interaction; import org.scribble.protocol.model.Introduces; import org.scribble.protocol.model.MessageSignature; import org.scribble.protocol.model.ParameterDefinition; import org.scribble.protocol.model.Protocol; import org.scribble.protocol.model.ProtocolModel; import org.scribble.protocol.model.TypeImport; import org.scribble.protocol.model.TypeImportList; import org.scribble.protocol.model.TypeReference; import org.scribble.protocol.util.TypesUtil; /** * The default implementation of the scenario protocol model generation. * */ public class ProtocolModelGeneratorImpl implements ProtocolModelGenerator { private static final Logger LOG=Logger.getLogger(ProtocolModelGeneratorImpl.class.getName()); private static final String PREFIX = "savns"; private static final String NAMESPACE_PREFIX = "http://namespace/"; private static final String INTERFACE_SUFFIX = "Interface"; /** * {@inheritDoc} */ public Set<ProtocolModel> generate(Scenario scenario, ResourceLocator locator, FeedbackHandler handler, String namespace) { java.util.Set<ProtocolModel> ret=new java.util.HashSet<ProtocolModel>(); for (Event event : scenario.getEvent()) { processEvent(event, ret, scenario, locator, handler, namespace); } return(ret); } protected void processEvent(Event event, java.util.Set<ProtocolModel> models, Scenario scenario, ResourceLocator locator, FeedbackHandler handler, String namespace) { if (event instanceof Group) { for (Event evt : ((Group)event).getEvent()) { processEvent(evt, models, scenario, locator, handler, namespace); } } else if (event instanceof SendEvent) { SendEvent se=(SendEvent)event; ProtocolModel pm=getProtocolModel(se, models, scenario, namespace); Interaction in=new Interaction(); MessageSignature msig=new MessageSignature(); msig.setOperation(se.getOperationName()); if (se.getFaultName() != null && se.getFaultName().trim().length() > 0) { Annotation annotation=new Annotation(AnnotationDefinitions.FAULT); annotation.getProperties().put(AnnotationDefinitions.NAME_PROPERTY, se.getFaultName()); in.getAnnotations().add(annotation); } if (isRequest(scenario, pm.getProtocol(), se)) { Annotation annotation=new Annotation(AnnotationDefinitions.CORRELATION); annotation.getProperties().put(AnnotationDefinitions.REQUEST_PROPERTY, se.getOperationName()); in.getAnnotations().add(annotation); } else { Annotation annotation=new Annotation(AnnotationDefinitions.CORRELATION); annotation.getProperties().put(AnnotationDefinitions.REPLY_TO_PROPERTY, se.getOperationName()); in.getAnnotations().add(annotation); } for (Parameter p : se.getParameter()) { TypeReference tref=getTypeReference(p, pm, locator); msig.getTypeReferences().add(tref); } in.setMessageSignature(msig); // Need to find receive event's role for (Link link : scenario.getLink()) { if (link.getSource() == event) { String otherRole=((Role)((MessageEvent)link.getTarget()).getRole()).getName(); in.getToRoles().add(new org.scribble.protocol.model.Role(otherRole)); break; } } pm.getProtocol().getBlock().add(in); } else if (event instanceof ReceiveEvent) { ReceiveEvent re=(ReceiveEvent)event; ProtocolModel pm=getProtocolModel(re, models, scenario, namespace); Interaction in=new Interaction(); MessageSignature msig=new MessageSignature(); msig.setOperation(re.getOperationName()); if (re.getFaultName() != null && re.getFaultName().trim().length() > 0) { Annotation annotation=new Annotation(AnnotationDefinitions.FAULT); annotation.getProperties().put(AnnotationDefinitions.NAME_PROPERTY, re.getFaultName()); in.getAnnotations().add(annotation); } if (isRequest(scenario, pm.getProtocol(), re)) { Annotation annotation=new Annotation(AnnotationDefinitions.CORRELATION); annotation.getProperties().put(AnnotationDefinitions.REQUEST_PROPERTY, re.getOperationName()); in.getAnnotations().add(annotation); } else { Annotation annotation=new Annotation(AnnotationDefinitions.CORRELATION); annotation.getProperties().put(AnnotationDefinitions.REPLY_TO_PROPERTY, re.getOperationName()); in.getAnnotations().add(annotation); } for (Parameter p : re.getParameter()) { TypeReference tref=getTypeReference(p, pm, locator); msig.getTypeReferences().add(tref); } in.setMessageSignature(msig); // Need to find send event's role for (Link link : scenario.getLink()) { if (link.getTarget() == event) { String otherRole=((Role)((MessageEvent)link.getSource()).getRole()).getName(); in.setFromRole(new org.scribble.protocol.model.Role(otherRole)); break; } } pm.getProtocol().getBlock().add(in); } else if (event instanceof Import) { // TODO: Handle import } else if (event instanceof TimeElapsedEvent) { // TODO: Handle time elapsed event } } protected TypeReference getTypeReference(Parameter p, ProtocolModel model, ResourceLocator locator) { TypeReference ret=new TypeReference(); QName qname=QName.valueOf(p.getType()); ret.setName(qname.getLocalPart()); // Check if import required TypeImport ti=TypesUtil.getTypeImport(ret); if (ti == null) { ti = new TypeImport(); ti.setName(qname.getLocalPart()); DataType dt=new DataType(); dt.setDetails(p.getType()); ti.setDataType(dt); TypeImportList il=new TypeImportList(); il.setFormat(TypeSystem.XSD); il.getTypeImports().add(ti); model.getImports().add(il); // Obtain schema location for namespace String location=obtainSchemaLocation(p.getValue(), qname.getNamespaceURI(), locator); il.setLocation(location); // Create annotation to provide type details if (AnnotationDefinitions.getAnnotationWithProperty(model.getProtocol().getAnnotations(), AnnotationDefinitions.TYPE, AnnotationDefinitions.NAMESPACE_PROPERTY, qname.getNamespaceURI()) == null) { int nsCount=AnnotationDefinitions.getAnnotations(model.getProtocol().getAnnotations(), AnnotationDefinitions.TYPE).size(); org.savara.common.model.annotation.Annotation protocolAnn= new org.savara.common.model.annotation.Annotation(AnnotationDefinitions.TYPE); protocolAnn.getProperties().put(AnnotationDefinitions.NAMESPACE_PROPERTY, qname.getNamespaceURI()); protocolAnn.getProperties().put(AnnotationDefinitions.PREFIX_PROPERTY, PREFIX+nsCount); if (location != null) { protocolAnn.getProperties().put(AnnotationDefinitions.LOCATION_PROPERTY, location); } model.getProtocol().getAnnotations().add(protocolAnn); } } return(ret); } protected String obtainSchemaLocation(String path, String ns, ResourceLocator locator) { String ret=null; try { java.net.URI uri=locator.getResourceURI(path); java.io.File f=new java.io.File(uri.getPath()); if (f.exists()) { java.io.FileInputStream fis=new java.io.FileInputStream(f); byte[] b=new byte[fis.available()]; fis.read(b); fis.close(); org.w3c.dom.Node node=XMLUtils.getNode(new String(b)); if (node instanceof org.w3c.dom.Element) { String location=((org.w3c.dom.Element)node).getAttributeNS( "http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"); if (location != null) { StringTokenizer st=new StringTokenizer(location, " "); while (st.hasMoreTokens()) { String stns=st.nextToken(); if (st.hasMoreTokens()) { String stval=st.nextToken(); if (stns.equals(ns)) { java.io.File other=new java.io.File( f.getParentFile(), stval); ret = locator.getRelativePath(other.getCanonicalPath()); break; } } } } } } } catch(Exception e) { LOG.log(Level.SEVERE, "Failed to load message", e); } return (ret); } protected ProtocolModel getProtocolModel(MessageEvent event, java.util.Set<ProtocolModel> models, Scenario scenario, String namespace) { ProtocolModel ret=null; String role=((Role)event.getRole()).getName(); for (ProtocolModel pm : models) { if (pm.getProtocol().getLocatedRole().getName().equals(role)) { ret = pm; break; } } if (ret == null) { ret = new ProtocolModel(); ret.setProtocol(new Protocol()); ret.getProtocol().setName(scenario.getName()); ret.getProtocol().setLocatedRole(new org.scribble.protocol.model.Role(role)); ret.getProtocol().setBlock(new Block()); createInterface(ret.getProtocol(), role, namespace); if (event instanceof ReceiveEvent) { // Need to find send event's role for (Link link : scenario.getLink()) { if (link.getTarget() == event) { ParameterDefinition pd=new ParameterDefinition(); pd.setName(((Role)((MessageEvent)link.getSource()).getRole()).getName()); ret.getProtocol().getParameterDefinitions().add(pd); break; } } } models.add(ret); } if (ret != null && event instanceof SendEvent) { // Need to find receive event's role for (Link link : scenario.getLink()) { if (link.getSource() == event) { // Check if role is client String otherRole=((Role)((MessageEvent)link.getTarget()).getRole()).getName(); // Check if role is client if (ret.getProtocol().getParameterDefinitions().size() == 0 || !ret.getProtocol().getParameterDefinitions().get(0).getName().equals(otherRole)) { // Check if other role is in the introduces list Introduces intro=null; if (ret.getProtocol().getBlock().size() > 0 && ret.getProtocol().getBlock().get(0) instanceof Introduces) { intro = (Introduces)ret.getProtocol().getBlock().get(0); } else { intro = new Introduces(); intro.setIntroducer(new org.scribble.protocol.model.Role( ret.getProtocol().getLocatedRole().getName())); ret.getProtocol().getBlock().getContents().add(0, intro); } if (intro.getIntroducedRole(otherRole) == null) { intro.getIntroducedRoles().add(new org.scribble.protocol.model.Role(otherRole)); createInterface(ret.getProtocol(), otherRole, namespace); } } break; } } } return(ret); } /** * This method creates an interface annotation for the supplied role * on the supplied protocol. * * @param p The protocol * @param role The role * @param namespace The optional */ protected void createInterface(Protocol p, String role, String namespace) { String ns=(namespace == null ? NAMESPACE_PREFIX : namespace); if (ns.endsWith("/")) { ns += role; } else { ns += "/"+role; } Annotation annotation=new Annotation(AnnotationDefinitions.INTERFACE); annotation.getProperties().put(AnnotationDefinitions.NAMESPACE_PROPERTY, ns); annotation.getProperties().put(AnnotationDefinitions.NAME_PROPERTY, role+INTERFACE_SUFFIX); annotation.getProperties().put(AnnotationDefinitions.ROLE_PROPERTY, role); p.getAnnotations().add(annotation); } /** * This method determines if this message event relates to a request. * * @param me The message event * @return Whether it is a request */ protected static boolean isRequest(Scenario scenario, Protocol p, MessageEvent me) { boolean ret=true; // Need to find event's other role String otherRole=null; for (Link link : scenario.getLink()) { if (me instanceof SendEvent && link.getSource() == me) { otherRole=((Role)((MessageEvent)link.getTarget()).getRole()).getName(); break; } else if (me instanceof ReceiveEvent && link.getTarget() == me) { otherRole=((Role)((MessageEvent)link.getSource()).getRole()).getName(); break; } } if (otherRole != null) { // Check whether there is a preceding message event of the same type // with the same operation name, and inverted roles, where that // message event is a request - in which case, this message event is // a response int pos=scenario.getEvent().indexOf(me); for (int i=pos-1; i >= 0; i--) { Event evt=scenario.getEvent().get(i); if (evt.getClass() == me.getClass()) { MessageEvent me2=(MessageEvent)evt; if (me2.getOperationName().equals(me.getOperationName())) { if (((Role)me2.getRole()).getName().equals(otherRole)) { ret = !isRequest(scenario, p, me2); break; } } } } /* // Check if client role if (p.getParameterDefinitions().size() > 0 && p.getParameterDefinitions().get(0).getName().equals(otherRole)) { ret = me instanceof ReceiveEvent; } else if (me instanceof SendEvent) { if (p.getBlock().size() > 0 && p.getBlock().get(0) instanceof Introduces) { Introduces intro = (Introduces)p.getBlock().get(0); ret = intro.getIntroducedRole(otherRole) != null; } } */ } return (ret); } }