001/*
002 * Copyright (c) 2003-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2015-07-02 19:21:28 +0000 (Thu, 02 Jul 2015) $' 
007 * '$Revision: 33522 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.objectmanager;
031
032import java.io.File;
033import java.io.FileInputStream;
034import java.io.FileNotFoundException;
035import java.io.FileWriter;
036import java.io.IOException;
037import java.io.InputStream;
038import java.io.Serializable;
039import java.io.StringWriter;
040import java.lang.reflect.Constructor;
041import java.util.Hashtable;
042import java.util.Iterator;
043import java.util.List;
044import java.util.StringTokenizer;
045import java.util.Vector;
046import java.util.jar.JarEntry;
047import java.util.jar.JarFile;
048import java.util.zip.ZipEntry;
049
050import org.apache.commons.logging.Log;
051import org.apache.commons.logging.LogFactory;
052import org.kepler.moml.CompositeClassEntity;
053import org.kepler.moml.NamedObjId;
054import org.kepler.moml.PortAttribute;
055import org.kepler.moml.PropertyAttribute;
056import org.kepler.objectmanager.lsid.KeplerLSID;
057import org.kepler.sms.SemanticType;
058import org.kepler.util.DotKeplerManager;
059import org.kepler.util.FileUtil;
060import org.kepler.util.TransientStringAttribute;
061
062import ptolemy.actor.Director;
063import ptolemy.actor.IOPort;
064import ptolemy.actor.TypedAtomicActor;
065import ptolemy.actor.TypedCompositeActor;
066import ptolemy.actor.TypedIOPort;
067import ptolemy.data.expr.Parameter;
068import ptolemy.data.expr.StringParameter;
069import ptolemy.data.expr.Variable;
070import ptolemy.kernel.ComponentEntity;
071import ptolemy.kernel.ComponentRelation;
072import ptolemy.kernel.CompositeEntity;
073import ptolemy.kernel.Entity;
074import ptolemy.kernel.InstantiableNamedObj;
075import ptolemy.kernel.Port;
076import ptolemy.kernel.util.Attribute;
077import ptolemy.kernel.util.IllegalActionException;
078import ptolemy.kernel.util.NameDuplicationException;
079import ptolemy.kernel.util.NamedObj;
080import ptolemy.kernel.util.SingletonConfigurableAttribute;
081import ptolemy.kernel.util.StringAttribute;
082import ptolemy.kernel.util.Workspace;
083import ptolemy.moml.MoMLParser;
084import ptolemy.moml.unit.UnitAttribute;
085import ptolemy.util.StringUtilities;
086import ptolemy.vergil.basic.KeplerDocumentationAttribute;
087
088/**
089 * This class parses and contains metadata for an actor. this creates an entity
090 * of the form:
091 * 
092 * <pre>
093 * &lt;entity name=&quot;Constant&quot;&gt;
094 *     &lt;property name=&quot;documentation&quot; class=&quot;ptolemy.vergil.basic.KeplerDocumentationAttribute&quot;&gt;
095 *     actor to provide constant input
096 *     &lt;/property&gt;
097 *     &lt;property name=&quot;entityId&quot; class=&quot;org.kepler.moml.NamedObjId&quot;
098 *                     value=&quot;urn:lsid:lsid.ecoinformatics.org:actor:101:1&quot;/&gt;
099 *     &lt;property name=&quot;class&quot; value=&quot;org.kepler.actor.TestActor&quot;
100 *               class=&quot;ptolemy.kernel.util.StringAttribute&quot;&gt;
101 *       &lt;property name=&quot;id&quot; value=&quot;urn:lsid:lsid.ecoinformatics.org:actor:1001:1&quot;
102 *                 class=&quot;ptolemy.kernel.util.StringAttribute&quot;/&gt;
103 *     &lt;/property&gt;
104 *     &lt;property name=&quot;output&quot; class=&quot;org.kepler.moml.PortProperty&gt;
105 *       &lt;property name=&quot;direction&quot; value=&quot;output&quot; class=&quot;ptolemy.kernel.util.StringAttribute&quot;/&gt;
106 *       &lt;property name=&quot;dataType&quot; value=&quot;unknown&quot; class=&quot;ptolemy.kernel.util.StringAttribute&quot;/&gt;
107 *       &lt;property name=&quot;isMultiport&quot; value=&quot;false&quot; class=&quot;ptolemy.kernel.util.StringAttribute&quot;/&gt;
108 *     &lt;/property&gt;
109 *     &lt;property name=&quot;trigger&quot; class=&quot;org.kepler.moml.PortProperty&gt;
110 *       &lt;property name=&quot;direction&quot; value=&quot;input&quot; class=&quot;ptolemy.kernel.util.StringAttribute&quot;/&gt;
111 *       &lt;property name=&quot;dataType&quot; value=&quot;unknown&quot; class=&quot;ptolemy.kernel.util.StringAttribute&quot;/&gt;
112 *       &lt;property name=&quot;isMultiport&quot; value=&quot;true&quot; class=&quot;ptolemy.kernel.util.StringAttribute&quot;/&gt;
113 *     &lt;/property&gt;
114 *     &lt;property class=&quot;org.kepler.sms.SemanticType&quot; name=&quot;semanticType&quot; value=&quot;urn:lsid:lsid.ecoinformatics.org:onto:1:1#ConstantActor&quot;/&gt;
115 *     &lt;property class=&quot;org.kepler.moml.Dependency&quot; name=&quot;dependency&quot; value=&quot;urn:lsid:lsid.ecoinformatics.org:nativeLib:1:1&quot;/&gt;
116 *     &lt;/entity&gt;
117 * </pre>
118 * 
119 * Note: As of 8/18/09, this class no longer includes graphical ammentities,
120 * such as icons in the moml. If you want graphical widgets for your actor, you
121 * must use org.kepler.gui.GraphicalActorMetadata.
122 * 
123 * @author Chad Berkley
124 *@created April 07, 2005
125 */
126public class ActorMetadata implements Serializable {
127
128        private static final Log log = LogFactory.getLog(ActorMetadata.class
129                        .getName());
130        private static final boolean isDebugging = log.isDebugEnabled();
131
132        /**
133         * The id of the class that implements this actor.
134         */
135        private String _classId;
136
137        /**
138         * The java class name. For composites, this is the name of the xml file
139         * like org.kepler.actor.MyCompositeActor
140         */
141        private String _className;
142
143        /**
144         * The class name as represented in ptII. For composites, this is always
145         * ptolemy.actor.TypedCompositeActor. For java classes, this is the name of
146         * the java class.
147         */
148        private String _internalClassName;
149
150        /**
151         * The id of the actor.
152         */
153        private String _actorId;
154
155        /**
156         * The name of the actor
157         */
158        private String _actorName;
159
160        /**
161         * The instantiation of the actor. TODO describe more about how/when this is
162         * populated, etc.
163         */
164        private NamedObj _actor;
165        
166        /**
167         * True if the actor described by this ActorMetadata is a class description.
168         */
169        private boolean _isClass;
170
171        /**
172         * dependency ids
173         */
174        private Vector<ClassedProperty> _dependencyVector;
175
176        /**
177         * semantic types
178         */
179        private Vector<ClassedProperty> _semanticTypeVector;
180
181        /**
182         * ports
183         */
184        private Vector<PortMetadata> _portVector;
185
186        /**
187         * changed flag
188         */
189        private boolean _changed = false;
190
191        /**
192         * attribute vector for generic attributes
193         */
194        private Vector<Attribute> _attributeVector;
195
196        /**
197         * vector for relations in a composite
198         */
199        private Vector<ComponentRelation> _relationVector;
200
201        /**
202         * 
203         */
204        private String _links = null;
205
206        /**
207         * 
208         */
209        private Vector<MetadataHandler> _metadataHandlerVector;
210        
211        /**
212         * default constructor. this is for serialization only. do not use this.
213         */
214        public ActorMetadata() {
215                initialize();
216                // nothing here.
217        }
218
219        private void initialize() {
220                _dependencyVector = new Vector<ClassedProperty>();
221                _semanticTypeVector = new Vector<ClassedProperty>();
222                _portVector = new Vector<PortMetadata>();
223                _attributeVector = new Vector<Attribute>();
224                _relationVector = new Vector<ComponentRelation>();
225                _metadataHandlerVector = new Vector<MetadataHandler>();
226                _isClass = false;
227        }
228
229        /**
230         * Constructor. Takes in xml metadata. This should be a moml entity with the
231         * kepler additional metadata properties. The entity is parsed and an
232         * ActorMetadata object is created with appropriate fields.
233         * 
234         * @param moml
235         *            the xml metadata
236         */
237        public ActorMetadata(InputStream moml) throws InvalidMetadataException {
238                if (isDebugging && moml != null)
239                        log.debug("ActorMetadata(" + moml.toString() + ")");
240
241                initialize();
242
243                try {
244                        String momlStr = FileUtil.convertStreamToString(moml);
245
246                        if (isDebugging) {
247                                // log.debug("\n********************************");
248                                // log.debug(momlStr);
249                                // log.debug("********************************\n");
250                                log.debug("**** MoMLParser ****");
251                        }
252
253                        /**
254                         * The MoMLParser cannot be the first thing to be called on Kepler
255                         * generated MoML files. Because TypedIOPorts are converted to
256                         * PortAttributes, an error is thrown when trying to parse Kepler
257                         * generated MoMLs that have any added ports. TODO: How to fix this?
258                         */
259                        MoMLParser parser = new MoMLParser(new Workspace());
260                        parser.reset();
261
262                        if (isDebugging)
263                                log.debug("got moml parser outputing moml");
264
265                        NamedObj obj = null;
266                        try {
267                                obj = parser.parse(null, momlStr);
268                        } catch (Exception e) {
269                                log.error(e.getMessage());
270                        }
271                        if (obj == null)
272                                return;
273
274                        if (isDebugging) {
275                                String filename = "parsed-actor_" + obj.getName() + ".moml";
276                                writeDebugMomlFor(obj, filename);
277                        }
278
279                        if (obj instanceof TypedCompositeActor) {
280                                _links = ((TypedCompositeActor) obj).exportLinks(1, null);
281                        }
282                        _actorName = obj.getName();
283                        
284                        StringAttribute classAttribute = (StringAttribute) obj.getAttribute("class");
285                        
286                        if(classAttribute == null) {
287                                throw new InvalidMetadataException("Missing 'class' attribute for " +
288                                                obj.getFullName());
289                        }
290                        
291                        Attribute idAtt = classAttribute.getAttribute("id");
292                        
293                        if(idAtt == null) {
294                                throw new InvalidMetadataException("Missing 'id' attribute for " +
295                                                obj.getFullName());
296                        }
297                        
298                        _classId = ((StringAttribute) idAtt).getExpression();
299                        
300                        _className = classAttribute.getExpression();
301                        _internalClassName = obj.getClassName();
302                        
303                        Attribute actIdAtt = obj.getAttribute(NamedObjId.NAME);
304                        
305                        if(actIdAtt == null) {
306                                throw new InvalidMetadataException("Missing '" +
307                                                NamedObjId.NAME + "' attribute for " + obj.getFullName());
308                        }
309                        
310                        _actorId = ((NamedObjId) actIdAtt).getExpression();
311                        
312                        NamedObj actor = getActorClass(_className, _actorName, obj);
313                        
314                        // Handle class definitions
315                        if (actor instanceof InstantiableNamedObj) {
316                                InstantiableNamedObj ino = (InstantiableNamedObj) actor;
317                                if (ino.isClassDefinition()) {
318                                        _isClass = true;
319                                        //_internalClassName = _className;
320                                }
321                        }
322                        this.setActor(actor);
323
324                        if (isDebugging) {
325                                String filename = "instantiated-actor-before_"
326                                                + getActor().getName() + ".moml";
327                                writeDebugMomlFor(obj, filename);
328                        }
329
330                        // get the semantic type and dependency lsids and any general
331                        // properties
332                        for (Object o : obj.attributeList()) {
333
334                                Attribute a = null;
335                                if (o instanceof Attribute) {
336                                        a = (Attribute) o;
337                                } else {
338                                        log.error("Object is not an Attribute");
339                                        continue;
340                                }
341
342                                getSemanticTypesAndDependencyLsids(a);
343
344                        }
345
346                        // get the ports
347
348                        // NOTE: we parse obj instead of actor since actor does not have
349                        // the PortAttributes
350                        parseNamedObj(obj);
351                        addAllRelations();
352                        
353                        if (isDebugging) {
354                                String filename = "instantiated-actor-after_"
355                                                + getActor().getName() + ".moml";
356                                writeDebugMomlFor(obj, filename);
357                        }
358
359                } catch (IOException ioe) {
360                        throw new InvalidMetadataException("Error reading data from lsid "
361                                        + _actorId + ": " + ioe.getMessage(), ioe);
362                } catch (Exception e) {
363                        if (isDebugging)
364                                log.debug(e.getStackTrace());
365                        throw new InvalidMetadataException(
366                                        "Error in parsing actor metadata: " + e.getMessage(), e);
367                }
368        }
369        
370        /**
371         * TODO: What is this doing?
372         * 
373         * @param a
374         * @return
375         */
376        private boolean checkAtt(Attribute a) {
377                String attName = a.getName();
378                String acn = a.getClassName();
379                if (!attName.equals(NamedObjId.NAME) && !attName.equals("class")
380                                && !acn.equals("org.kepler.moml.PropertyEntity")
381                                && !acn.equals("org.kepler.moml.PropertyAttribute")
382                                && !acn.equals("org.kepler.moml.CompositeClassEntity")
383                                && !acn.equals("org.kepler.moml.PortAttribute")) {
384                        return true;
385                }
386                return false;
387        }
388
389        /**
390         * TODO: What is this doing?
391         * 
392         * @param a
393         * @throws IllegalActionException
394         * @throws NameDuplicationException
395         * @throws CloneNotSupportedException
396         */
397        private void getSemanticTypesAndDependencyLsids(Attribute a)
398                        throws IllegalActionException, NameDuplicationException,
399                        CloneNotSupportedException {
400
401                String attName = a.getName();
402                String attClassName = a.getClassName();
403                String aClassName = a.getClass().getName();
404                String kd = "ptolemy.vergil.basic.KeplerDocumentationAttribute";
405
406                if (attClassName.equals(kd)) {
407                        // parse the documentation
408
409                        setDocumentationAttribute((KeplerDocumentationAttribute) a);
410                } else if (checkAtt(a)) {
411
412                        String attValue = null;
413                        if (a instanceof StringAttribute) {
414                                attValue = ((StringAttribute) a).getExpression();
415
416                        } else if (a instanceof UnitAttribute) {
417                                attValue = ((UnitAttribute) a).getExpression();
418
419                        } else if (a instanceof Variable) {
420                                attValue = ((Variable) a).getExpression();
421                        }
422
423                        if (attName.indexOf("semanticType") != -1) {
424                                addSemanticType(a.getName(), attValue);
425
426                        } else if (attName.indexOf("dependency") != -1) {
427                                ClassedProperty prop = new ClassedProperty(attName, attValue,
428                                                aClassName);
429                                _dependencyVector.add(prop);
430
431                        } else if (attName.indexOf("_iconDescription") != -1) {
432                                NamedObj act = getActor();
433                                Attribute iconAtt = act.getAttribute("_iconDescription");
434
435                                if (act != null && iconAtt != null) {
436                                        handleIconDescription(a);
437
438                                } else {
439                                        addAttribute(a);
440                                }
441                        } else {
442                                // add generic attributes
443                                addAttribute(a);
444                        }
445                }
446        }
447
448        /**
449         * TODO: What is this doing?
450         * 
451         * @param a
452         */
453        private void handleIconDescription(Attribute a) {
454                boolean objIsDefault = false;
455                boolean actorIsDefault = false;
456
457                String objIconStr = ((SingletonConfigurableAttribute) a)
458                                .getExpression();
459                String actorIconStr = ((SingletonConfigurableAttribute) getActor()
460                                .getAttribute("_iconDescription")).getExpression();
461
462                // Should this come from somewhere else?
463                String pp = "<polygon" + " points=\"-20,-10 20,0 -20,10\""
464                                + " style=\"fill:blue\"/>";
465
466                if (objIconStr.indexOf(pp) != -1) {
467                        objIsDefault = true;
468                }
469
470                if (actorIconStr.indexOf(pp) != -1) {
471                        actorIsDefault = true;
472                }
473
474                if ((objIsDefault && actorIsDefault)
475                                || (objIsDefault && actorIsDefault)
476                                || (!objIsDefault && !actorIsDefault)) {
477                        addAttribute(a);
478                } else if (objIsDefault && !actorIsDefault) {
479                        // do nothing. leave the attribute in the actor
480                }
481        }
482
483        /**
484         * builds a new ActorMetadata object from an existing NamedObj
485         * 
486         * @param am
487         *            the ActorMetadata to build this object from.
488         */
489        public ActorMetadata(NamedObj obj) {
490                
491                //System.out.println(obj.exportMoML());
492                
493                initialize();
494                
495                if (obj instanceof InstantiableNamedObj) {
496                        InstantiableNamedObj ino = (InstantiableNamedObj) obj;
497                        if (ino.isClassDefinition()) {
498                                _isClass = true;
499                        }
500                }
501                
502                this.setActor(obj);
503
504                if (obj.getAttribute(NamedObjId.NAME) != null) {
505                        _actorId = ((NamedObjId) obj.getAttribute(NamedObjId.NAME))
506                                        .getExpression();
507                }
508                _actorName = obj.getName();
509
510                if (_isClass) {
511                        
512                        Attribute classAtt = obj.getAttribute("tempClassName");
513                        if (classAtt != null) {
514                                TransientStringAttribute classAttribute = (TransientStringAttribute) classAtt;
515                                String className = classAttribute.getExpression();
516                                _className = className;
517                                _internalClassName = className;
518                        }
519                        
520                        _links = null;
521
522                        addAllAttributes();
523                        addAllRelations();
524                        removeLinks();
525
526                } else {
527                        _className = obj.getClassName();
528                        _internalClassName = obj.getClassName();
529                        try {
530                                if (obj instanceof TypedCompositeActor) {
531                                        _links = ((TypedCompositeActor) obj).exportLinks(1, null);
532                                }
533                        } catch (Exception e) {
534                                System.out.println("Error looking at links: " + e.getMessage());
535                        }
536        
537                        // set the internalClassname
538                        if (obj instanceof TypedAtomicActor) {
539                                _internalClassName = "ptolemy.actor.TypedAtomicActor";
540                        } else if (obj instanceof Attribute) {
541                                _internalClassName = "org.kepler.moml.PropertyEntity";
542                        } else if (obj instanceof TypedCompositeActor
543                                        || obj instanceof CompositeEntity) {
544                                _internalClassName = "org.kepler.moml.CompositeClassEntity";
545                        }
546
547                        addAllAttributes();
548                        addAllRelations();
549                }
550                parseActor();           
551        }
552
553        /**
554         * return the actor this object was built from.
555         */
556        public NamedObj getActor() {
557                return _actor;
558        }
559
560        public void setActor(NamedObj actor) {
561                _actor = actor;
562        }
563
564        /**
565         * return the name of the actor
566         */
567        public String getName() {
568                return _actorName;
569        }
570
571        /**
572         * set the name
573         */
574        public void setName(String name) {
575                _actorName = name;
576        }
577
578        /**
579         * return the lsid of the actor class object
580         */
581        public String getId() {
582                return _actorId;
583        }
584
585        /**
586         * returns the id of this object as a KeplerLSID
587         */
588        public KeplerLSID getLSID() throws Exception {
589                return new KeplerLSID(_actorId);
590        }
591
592        /**
593         *
594         */
595        public KeplerDocumentationAttribute getDocumentationAttribute() {
596                KeplerDocumentationAttribute da = (KeplerDocumentationAttribute) getActor()
597                                .getAttribute("KeplerDocumentation");
598                return da;
599        }
600
601        /**
602         *
603         */
604        public void setDocumentationAttribute(KeplerDocumentationAttribute newda)
605                        throws IllegalActionException, NameDuplicationException,
606                        CloneNotSupportedException {
607                
608                NamedObj a = getActor();
609                if (a == null) 
610                        return;
611                
612                Attribute da = a.getAttribute("documentation");
613
614                // if the actor already has a da, then get rid of it and set this one
615                // instead
616                if (da != null)
617                        da.setContainer(null);
618
619                da = a.getAttribute("KeplerDocumentation");
620                if (da != null)
621                        da.setContainer(null);
622
623                Workspace w = a.workspace();
624                KeplerDocumentationAttribute n = (KeplerDocumentationAttribute) newda
625                                .clone(w);
626                n.setContainer(a);
627        }
628
629        /**
630         * set the id
631         */
632        public void setId(String id) {
633                _actorId = id;
634        }
635
636        /**
637         * return the classname of the actor object. this will be the java type
638         * classname no matter what kind of actor we are describing. for instance if
639         * it is a java class, it will be a.b.c.ClassName where the file is stored
640         * in a/b/c/ClassName.class. If it is a MoML class, it will be
641         * a.b.c.MomlClassName where the file is a/b/c/MomlClassName.xml
642         */
643        public String getClassName() {
644                return _className;
645        }
646
647        /**
648         * return the internal class name of the actor object. for composites this
649         * will be ptolemy.actor.TypedCompositeActor. For atomics, it will be the
650         * full java class name.
651         */
652        public String getInternalClassName() {
653                return _internalClassName;
654        }
655
656        /**
657         * return the id of the class
658         */
659        public String getClassId() {
660                return _classId;
661        }
662
663        public void setClassId(String id) {
664                _classId = id;
665        }
666
667        /**
668         * add the id of a dependency to the metadata
669         * 
670         * @param id
671         *            the id of the dependency to add
672         */
673        public void addDependency(String id) {
674                ClassedProperty cp = new ClassedProperty("dependency", id,
675                                "org.kepler.moml.Dependency");
676                _dependencyVector.addElement(cp);
677        }
678
679        /**
680         * add the id of a semantic type to the metadata
681         * 
682         * @param id
683         *            the id of the semantic type to add
684         */
685        public void addSemanticType(String name, String id) {
686                ClassedProperty cp = new ClassedProperty(name, id,
687                                "org.kepler.sms.SemanticType");
688                _semanticTypeVector.addElement(cp);
689        }
690
691        /**
692         * return a vector of the ids of the semantic type reference
693         */
694        public Vector<String> getSemanticTypes() {
695                Vector<String> v = new Vector<String>();
696                for (int i = 0; i < _semanticTypeVector.size(); i++) {
697                        v
698                                        .addElement(((ClassedProperty) _semanticTypeVector
699                                                        .elementAt(i)).value);
700                }
701                return v;
702        }
703
704        public Hashtable<String, String> getSemanticTypeHash() {
705                Hashtable<String, String> h = new Hashtable<String, String>();
706                for (int i = 0; i < _semanticTypeVector.size(); i++) {
707                        ClassedProperty cp = (ClassedProperty) _semanticTypeVector
708                                        .elementAt(i);
709                        h.put(cp.name, cp.value);
710                }
711                return h;
712        }
713
714        public void removeSemanticType(String id) {
715                for (int i = 0; i < _semanticTypeVector.size(); i++) {
716                        ClassedProperty cp = (ClassedProperty) _semanticTypeVector
717                                        .elementAt(i);
718                        if (cp.name.equals(id)) {
719                                _semanticTypeVector.remove(i);
720                                break;
721                        }
722                }
723        }
724
725        /**
726         * return a vector of the ids of the semantic type reference
727         */
728        public Vector<String> getDependencies() {
729                Vector<String> v = new Vector<String>();
730                for (int i = 0; i < _dependencyVector.size(); i++) {
731                        v
732                                        .addElement(((ClassedProperty) _dependencyVector
733                                                        .elementAt(i)).value);
734                }
735                return v;
736        }
737
738        /**
739         * get the changed flag. this is useful for keeping track of the state of
740         * the actor metadata. this flag does not affect this class in any internal
741         * way except for setting the flag.
742         */
743        public boolean getChanged() {
744                return _changed;
745        }
746
747        /**
748         * set the changed flag. this is useful for keeping track of the state of
749         * the actor metadata. this flag does not affect this class in any internal
750         * way except for setting the flag.
751         * 
752         * @param b
753         */
754        public void setChanged(boolean b) {
755                _changed = b;
756        }
757
758        /**
759         * add a generic attribute to this actorMetadata object.
760         * 
761         * @param a
762         *            the attribute to add
763         */
764        public void addAttribute(Attribute a) {
765                // why did we intentionally skip PortParameters?
766                // if
767                // (a.getClassName().equals("ptolemy.actor.parameters.PortParameter")) {
768                // return;
769                // }
770                _attributeVector.add(a);
771        }
772
773        /**
774         * add a relation
775         */
776        public void addRelation(ComponentRelation r) {
777                _relationVector.add(r);
778        }
779
780        /**
781         * return this actor as a ComponentEntity
782         * 
783         * @param container
784         *            the new ComponentEntity's container
785         */
786        public NamedObj getActorAsNamedObj(CompositeEntity container)
787                        throws Exception {
788                
789                NamedObj obj = null;
790
791                // Throw a NullPointerException here with a good message.
792                // If actor is null, clone() will fail anyway.
793                if (getActor() == null) {
794                        throw new NullPointerException(
795                                        "Could not clone '"
796                                                        + _actorName
797                                                        + "' from the '"
798                                                        + _className
799                                                        + "' class; the object is null, possibly meaning it was not "
800                                                        + "found. Perhaps there is a classpath problem and/or the "
801                                                        + "karlib needs to be flushed?");
802
803                } else if (getActor() instanceof TypedCompositeActor) {
804                        
805                        /*
806                         * if we are dealing with a composite entity, do stuff a bit
807                         * differently we need to instantiate the composite or else it will
808                         * show up in the library as a class instead of an entity. this
809                         * causes kepler to think that the user wants to drag a class to the
810                         * canvas and it requires the user to instantiate the actor before
811                         * using it. by calling instantiate here, we bypass that.
812                         */
813                        if (_internalClassName
814                                        .equals("org.kepler.moml.CompositeClassEntity")) {
815                                obj = getActor();
816                                obj = addPorts(obj, _portVector);
817
818                                if (container == null) {
819                                        try {
820                                                NamedObj newobj = (NamedObj) getActor().clone(
821                                                                new Workspace());
822                                                // this kinda works
823                                                return newobj;
824                                        } catch (java.lang.CloneNotSupportedException cnse) {
825                                                System.out
826                                                                .println("trying to clone "
827                                                                                + getActor().getName()
828                                                                                + " but "
829                                                                                + "you can't clone this object for some reason: "
830                                                                                + cnse.getMessage());
831                                        }
832                                } else {
833                                        return (NamedObj) getActor().clone(container.workspace());
834                                        // this kinda works
835                                }
836                                // return
837                                // (NamedObj)((TypedCompositeActor)actor).instantiate(container,
838                                // actor.getName());
839                                // obj =
840                                // (NamedObj)((TypedCompositeActor)actor).instantiate(container,
841                                // actor.getName());
842                                // obj.setClassName(className);
843                                // return obj;
844                        } else {
845                            
846                            // see if the internal class name is a subclass of composite actor
847                    Class<?> clazz = Class.forName(_internalClassName);
848                    Class<?> compositeActorClass = Class.forName("ptolemy.actor.TypedCompositeActor");
849                    if(compositeActorClass.isAssignableFrom(clazz)) {
850                        // clone it
851                        if(container == null) { 
852                            return (NamedObj) getActor().clone(new Workspace());
853                        } else {
854                            return (NamedObj) getActor().clone(container.workspace());
855                        }
856                    } else {
857                                obj = (NamedObj) ((TypedCompositeActor) getActor())
858                                                .instantiate(container, getActor().getName());
859                                obj.setClassName(_className);
860                    }
861                        }
862
863                } else if (getActor() instanceof Director
864                                || getActor() instanceof Attribute) {
865                        // this is a director or other Attribute derived class
866
867                        // obj = new Director(container, actorName);
868                        // obj.setClassName(className);
869                        if (container == null) {
870                                obj = (NamedObj) getActor().clone(new Workspace());
871                        } else {
872                                obj = (NamedObj) getActor().clone(container.workspace());
873                        }
874
875                } else {
876                        // this is an atomic actor
877                        if (container != null) {
878                                obj = (NamedObj) getActor().clone(container.workspace());
879                                ((TypedAtomicActor) obj).setContainer(container);
880                        } else {
881                                obj = (NamedObj) getActor().clone(null);
882                        }
883                }
884
885                // call the metadata handlers
886                for (int i = 0; i < _metadataHandlerVector.size(); i++) {
887                        MetadataHandler handler = (MetadataHandler) _metadataHandlerVector
888                                        .elementAt(i);
889                        handler.handleMetadata(obj);
890                }
891
892                NamedObjId objId;
893                StringAttribute classObj;
894                StringAttribute classIdObj;
895
896                try {
897                        objId = new NamedObjId(obj, NamedObjId.NAME);
898                } catch (ptolemy.kernel.util.IllegalActionException iee) {
899                        objId = (NamedObjId) obj.getAttribute(NamedObjId.NAME);
900                } catch (ptolemy.kernel.util.NameDuplicationException nde) {
901                        objId = (NamedObjId) obj.getAttribute(NamedObjId.NAME);
902                }
903
904                try {
905                        classObj = new StringAttribute(obj, "class");
906                        classIdObj = new StringAttribute(classObj, "id");
907                } catch (ptolemy.kernel.util.InternalErrorException iee) {
908                        classObj = (StringAttribute) obj.getAttribute("class");
909                        classIdObj = (StringAttribute) classObj.getAttribute("id");
910                } catch (ptolemy.kernel.util.NameDuplicationException nde) {
911                        classObj = (StringAttribute) obj.getAttribute("class");
912                        classIdObj = (StringAttribute) classObj.getAttribute("id");
913                }
914
915                if (objId != null) {
916                        objId.setExpression(_actorId);
917                }
918
919                classObj.setExpression(_className);
920                classIdObj.setExpression(_classId);
921                for (int i = 0; i < _semanticTypeVector.size(); i++) {
922                        ClassedProperty cp = (ClassedProperty) _semanticTypeVector
923                                        .elementAt(i);
924                        Attribute attribute = obj.getAttribute(cp.name);
925                        if (attribute == null) {
926                                SemanticType semType = new SemanticType(obj, cp.name);
927                                semType.setExpression(cp.value);
928                        }
929                        else if (!(attribute instanceof SemanticType)) {
930                                log.warn("Attribute is not a SemanticType as expected");
931                        }
932                }
933                /*
934                 * FIXME: TODO: add dependencies and other info to the NamedObj
935                 */
936
937                // add the general attributes to the object
938                for (int i = 0; i < _attributeVector.size(); i++) {
939                        Attribute a = (Attribute) _attributeVector.elementAt(i);
940                        Attribute aClone = (Attribute) a.clone(obj.workspace());
941                        try {
942                                aClone.setContainer(obj);
943                        } catch (NameDuplicationException nde) {
944                                // System.out.println("obj already has attribute " +
945                                // a.getName());
946                                // ignore this, it shouldn't matter.
947                                // Specialized versions of some actors (e.g. RExpression actor
948                                // require that parameters be reset to new values
949                                // without the following code, these will not be reset
950                                // Dan Higgins - 1/20/2006
951                                String attValue;
952                                String attName;
953                                attName = aClone.getName();
954                                if (aClone instanceof StringAttribute) {
955                                        attValue = ((StringAttribute) aClone).getExpression();
956                                        StringAttribute sa = (StringAttribute) obj
957                                                        .getAttribute(attName);
958                                        sa.setExpression(attValue);
959                                } else if (aClone instanceof StringParameter) {
960                                        attValue = ((StringParameter) aClone).getExpression();
961                                        StringParameter sp = (StringParameter) obj
962                                                        .getAttribute(attName);
963                                        sp.setExpression(attValue);
964                                } else if (aClone instanceof Parameter) {
965                                        attValue = ((Parameter) aClone).getExpression();
966                                        Parameter pp = (Parameter) obj.getAttribute(attName);
967                                        pp.setExpression(attValue);
968                                }
969
970                        }
971                }
972
973                // copy any extra moml ports over
974                if (!(getActor() instanceof Director)) {
975                        obj = addPorts(obj, _portVector);
976                }
977
978                return obj;
979        }
980
981        /**
982         * return the moml xml representation of the actor.
983         */
984        public String toString() {
985        if (isDebugging) {
986            log.debug("toString()");
987        }
988                return toString(true, true, true);
989        }
990        
991        /**
992         * return the moml xml representation of the actor.
993         * @param incSemanticTypeNames if true, add a suffix to property names
994         * for semantic types, e.g. semanticType00 -> semanticType000 
995         * @param includeAttributes if true, add the attributes and parameters
996         * to the xml representation. this flag does not affect semantic types
997         * or documentation attributes.
998         * @param includePorts if true, add the ports to the xml representation.
999         */
1000        public String toString(boolean addSuffixToSemanticTypeNames,
1001                boolean includeAttributes, boolean includePorts) {
1002
1003                StringBuffer sb = new StringBuffer();
1004
1005                sb.append("<?xml version=\"1.0\"?>\n");
1006
1007                sb.append("<!DOCTYPE entity PUBLIC "
1008                                + "\"-//UC Berkeley//DTD MoML 1//EN\"\n"
1009                                + "    \"http://ptolemy.eecs.berkeley.edu"
1010                                + "/xml/dtd/MoML_1.dtd\">\n");
1011                NamedObj actor = getActor();
1012                if (actor instanceof PropertyAttribute) {
1013
1014                        sb.append("<property name=\"" + _actorName
1015                                        + "\" class=\"org.kepler.moml.PropertyAttribute\">\n");
1016
1017                } else if (actor instanceof Attribute) {
1018
1019                        sb.append("<property name=\"" + _actorName
1020                                        + "\" class=\"org.kepler.moml.PropertyEntity\">\n");
1021
1022                } else if (_internalClassName
1023                                .equals("org.kepler.moml.CompositeClassEntity")) {
1024
1025                        sb.append("<entity name=\"" + _actorName
1026                                        + "\" class=\"org.kepler.moml.CompositeClassEntity\">\n");
1027
1028                } else {
1029
1030                        if (_isClass) {
1031                                //System.out.println("isClass: " + _internalClassName);
1032                                sb.append("<entity name=\"" + _actorName
1033                                                + "\" class=\"" + _internalClassName + "\">\n");
1034                        } else if(actor instanceof TypedAtomicActor) {
1035                sb.append("<entity name=\"" + _actorName
1036                        + "\" class=\"ptolemy.actor.TypedAtomicActor\">\n");                        
1037                        } else {
1038                            // FIXME what about composites?
1039                                sb.append("<entity name=\"" + _actorName
1040                                                + "\" class=\"ptolemy.kernel.ComponentEntity\">\n");
1041                        }
1042
1043                }
1044
1045                sb.append("<property name=\"" + NamedObjId.NAME + "\"  value=\""
1046                                + _actorId + "\" class=\"org.kepler.moml.NamedObjId\"/>\n");
1047
1048                if (_internalClassName.equals("ptolemy.actor.Director")
1049                                || _internalClassName
1050                                                .equals("ptolemy.actor.TypedCompositeActor")
1051                                || _internalClassName.equals("ptolemy.kernel.ComponentEntity")
1052                                || _internalClassName.equals("ptolemy.actor.TypedAtomicActor")
1053                                || _internalClassName.equals("org.kepler.moml.PropertyEntity")
1054                                || _internalClassName
1055                                                .equals("org.kepler.moml.CompositeClassEntity")) {
1056                        sb.append("<property name=\"class\" value=\"" + _className
1057                                        + "\" class=\"ptolemy.kernel.util.StringAttribute\">\n");
1058                } else {
1059                        sb.append("<property name=\"class\" value=\"" + _internalClassName
1060                                        + "\" class=\"ptolemy.kernel.util.StringAttribute\">\n");
1061                }
1062
1063                // add another property to tell what the moml class is
1064                if (_internalClassName.equals("ptolemy.actor.TypedCompositeActor")) {
1065                        sb.append("  <property name=\"momlClass\" value=\"" + _className
1066                                        + "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
1067                }
1068                sb.append("  <property name=\"id\" value=\"" + _classId
1069                                + "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
1070                sb.append("</property>\n");
1071
1072                // print the dependencies
1073                if (_dependencyVector.size() != 0) {
1074                        for (int i = 0; i < _dependencyVector.size(); i++) {
1075                                ClassedProperty cp = (ClassedProperty) _dependencyVector.get(i);
1076                                cp.addNameIterator(i);
1077                                sb.append(cp.toString() + "\n");
1078                        }
1079                }
1080
1081                // print the semantic types
1082                if (_semanticTypeVector.size() != 0) {
1083                        for (int i = 0; i < _semanticTypeVector.size(); i++) {
1084                                ClassedProperty cp = (ClassedProperty) _semanticTypeVector
1085                                                .get(i);
1086                                if(addSuffixToSemanticTypeNames) {
1087                                        cp.addNameIterator(i);
1088                                }
1089                                sb.append(cp.toString() + "\n");
1090                        }
1091                }
1092
1093                // add general attributes
1094                if (_attributeVector.size() != 0) {
1095                        for (int i = 0; i < _attributeVector.size(); i++) {
1096                                Attribute a = (Attribute) _attributeVector.elementAt(i);
1097                                if(includeAttributes || (a instanceof SemanticType)) {
1098                                    sb.append(a.exportMoML() + "\n");
1099                                }
1100                        }
1101                }
1102
1103                // print the ports
1104                // NOTE: the ports must come after attributes since ParameterPorts
1105                // must come after the PortParameters. otherwise parsing the xml
1106                // results in a NameDuplicatonException.
1107                // see http://bugzilla.ecoinformatics.org/show_bug.cgi?id=4580
1108
1109                if (includePorts && _portVector.size() != 0) {
1110                        for (int i = 0; i < _portVector.size(); i++) {
1111                                if (getActor() instanceof TypedCompositeActor
1112                                                && getActor() instanceof InstantiableNamedObj
1113                                                && !((InstantiableNamedObj) getActor())
1114                                                                .isClassDefinition()) {
1115                                        sb.append(((PortMetadata) _portVector.get(i))
1116                                                        .toMoMLString());
1117                                } else {
1118                                        sb.append(((PortMetadata) _portVector.get(i)).toString());
1119                                }
1120                        }
1121                }
1122
1123                // add relations
1124                if (_relationVector.size() != 0) {
1125                        for (int i = 0; i < _relationVector.size(); i++) {
1126                                ComponentRelation r = (ComponentRelation) _relationVector
1127                                                .elementAt(i);
1128                                sb.append(r.exportMoML() + "\n");
1129                        }
1130
1131                }
1132
1133                // add documentation
1134                KeplerDocumentationAttribute da = getDocumentationAttribute();
1135                if (da != null) {
1136                        sb.append(da.exportMoML());
1137                }
1138
1139                String cce = "org.kepler.moml.CompositeClassEntity";
1140                if (_internalClassName.equals(cce)) {
1141                        CompositeEntity ce = (CompositeEntity) getActor();
1142
1143                        // add any class definitions 
1144                        // NOTE: these must be added before the entities since the
1145                        // MoMLParser needs to read them first.
1146            List<?> classDefinitions = ce.classDefinitionList();
1147            for(Object obj : classDefinitions) {
1148                String classDefinitionMoml = ((NamedObj)obj).exportMoML();
1149                sb.append(classDefinitionMoml);
1150            }
1151
1152                        List<?> entList = ce.entityList();
1153                        Iterator<?> entityItt = entList.iterator();
1154
1155                        while (entityItt.hasNext()) {
1156                                Entity ent = (Entity) entityItt.next();
1157                                String entMoml = ent.exportMoML();
1158                                sb.append(entMoml);
1159                        }
1160                        
1161                }
1162
1163                if (_links != null) {
1164                        sb.append(_links);
1165                }
1166
1167                if (getActor() instanceof Attribute
1168                                || getActor() instanceof PropertyAttribute) {
1169                        sb.append("</property>");
1170                } else {
1171                        sb.append("</entity>\n");
1172                }
1173
1174                return sb.toString();
1175        }
1176
1177        /**
1178         * this method allows other classes to add handlers to further process the
1179         * metadata produced by this class. The handlers will be called in the
1180         * getActorAsNamedObj() and getActorClass() methods.
1181         * 
1182         * @param handler
1183         *            the handler to add
1184         */
1185        public void addMetadataHandler(MetadataHandler handler) {
1186                _metadataHandlerVector.add(handler);
1187        }
1188
1189        /**
1190         * remove a metadata handler
1191         * 
1192         * @param handler
1193         *            the handler to remove
1194         */
1195        public void removeMetadataHandler(MetadataHandler handler) {
1196                _metadataHandlerVector.remove(handler);
1197        }
1198
1199        private boolean addPort(TypedIOPort p, PortMetadata pm)
1200                        throws IllegalActionException {
1201                if (isDebugging)
1202                        log.debug("*************p: " + p.exportMoML());
1203                boolean found = false;
1204
1205                String pName = p.getName();
1206                String cpName = cleansePortName(pm.name);
1207                if (pName.equals(cpName)) {
1208
1209                        if (isDebugging)
1210                                log.debug("adding port " + pm.name);
1211
1212                        Vector<NamedObj> pAtts = pm.attributes;
1213                        for (int j = 0; j < pAtts.size(); j++) {
1214                                try {
1215                                        if (isDebugging)
1216                                                log.debug("cloning port " + pm.name);
1217
1218                                        NamedObj noAtt = pAtts.elementAt(j);
1219
1220                                        Attribute pm_att = (Attribute) noAtt;
1221                                        if (isDebugging)
1222                                                log.debug("processing attribute: " + pm_att.getName());
1223                                        if (pm_att instanceof SemanticType) {
1224                                                ((Attribute) ((Attribute) pAtts.elementAt(j)).clone(p
1225                                                                .workspace())).setContainer(p);
1226                                                // System.out.println("added attribute " +
1227                                                // ((Attribute)pm.attributes.elementAt(j)).getName()
1228                                                // + " to port " + p.getName());
1229                                        }
1230                                        // System.out.println("cloned port " + pm.name);
1231                                        // System.out.println("<port> is now: " +
1232                                        // p.exportMoML());
1233                                } catch (NameDuplicationException nde) {
1234                                        // System.out.println("tried to duplicate " +
1235                                        // pm.attributes.elementAt(j).toString());
1236                                } catch (java.lang.CloneNotSupportedException cnse) {
1237                                }
1238                        }
1239                        found = true;
1240                }
1241                return found;
1242        }
1243
1244        /**
1245         * adds any kepler ports to the actor
1246         */
1247        private NamedObj addPorts(NamedObj obj, Vector<PortMetadata> portVector)
1248                        throws IllegalActionException, NameDuplicationException {
1249                boolean found = false;
1250
1251                for (int i = 0; i < portVector.size(); i++) {
1252
1253                        // if there are any ports in the port vector that are not in the
1254                        // port iterator, add them
1255
1256                        Entity ent = (Entity) obj;
1257                        List<?> pList = ent.portList();
1258                        Iterator<?> portIterator = pList.iterator();
1259                        PortMetadata pm = (PortMetadata) portVector.elementAt(i);
1260                        Vector<NamedObj> pmAtts = pm.attributes;
1261
1262                        if (isDebugging)
1263                                log.debug("**********pm: " + pm.toString());
1264
1265                        while (portIterator.hasNext()) {
1266
1267                                TypedIOPort p = (TypedIOPort) portIterator.next();
1268                                found = addPort(p, pm);
1269                                if (found)
1270                                        break;
1271
1272                        }
1273
1274                        if (!found) {
1275                                TypedIOPort port = null;
1276
1277                                if (obj instanceof TypedAtomicActor) {
1278                                        TypedAtomicActor taa = (TypedAtomicActor) obj;
1279                                        List<?> taaPL = taa.portList();
1280                                        Iterator<?> portList = taaPL.iterator();
1281
1282                                        boolean flag = true;
1283                                        while (portList.hasNext()) {
1284
1285                                                TypedIOPort oldport = (TypedIOPort) portList.next();
1286                                                String oldportName = oldport.getName();
1287
1288                                                if (oldportName.equals(pm.name))
1289                                                        flag = false;
1290
1291                                                List<?> opAttList = oldport.attributeList();
1292
1293                                                if (isDebugging) {
1294                                                        log.debug("old port atts: " + opAttList.size());
1295                                                        log.debug("pm att size: " + pmAtts.size());
1296                                                }
1297
1298                                                if (opAttList.size() != pmAtts.size())
1299                                                        flag = true;
1300                                        }
1301
1302                                        if (flag) {
1303
1304                                                if (isDebugging)
1305                                                        log.debug("adding port " + pm.name + " to obj");
1306
1307                                                String cpName = cleansePortName(pm.name);
1308                                                port = new TypedIOPort(taa, cpName);
1309
1310                                        } else {
1311
1312                                                if (isDebugging) {
1313                                                        log.debug("not adding port " + pm.name + " to obj");
1314                                                }
1315
1316                                        }
1317                                } else {
1318
1319                                        TypedCompositeActor tca = (TypedCompositeActor) obj;
1320                                        List<?> tcaPList = tca.portList();
1321                                        Iterator<?> portList = tcaPList.iterator();
1322
1323                                        boolean flag = true;
1324                                        while (portList.hasNext()) {
1325
1326                                                TypedIOPort oldport = (TypedIOPort) portList.next();
1327                                                String oldportName = oldport.getName();
1328
1329                                                if (oldportName.equals(pm.name))
1330                                                        flag = false;
1331                                        }
1332
1333                                        if (flag) {
1334                                                String cpName = cleansePortName(pm.name);
1335                                                port = new TypedIOPort(tca, cpName);
1336                                        }
1337                                }
1338
1339                                if (port == null) {
1340                                        continue;
1341                                }
1342
1343                                if (pm.direction.equals("input")) {
1344                                        port.setInput(true);
1345                                } else if (pm.direction.equals("output")) {
1346                                        port.setOutput(true);
1347                                } else if (pm.direction.equals("inputoutput")) {
1348                                        port.setInput(true);
1349                                        port.setOutput(true);
1350                                }
1351
1352                                if (pm.multiport) {
1353                                        port.setMultiport(true);
1354                                }
1355
1356                                Iterator<?> attItt = pmAtts.iterator();
1357                                while (attItt.hasNext()) {
1358
1359                                        Attribute a = (Attribute) attItt.next();
1360                                        try {
1361                                                Workspace pws = port.workspace();
1362                                                Attribute attClone = (Attribute) a.clone(pws);
1363                                                attClone.setContainer(port);
1364
1365                                        } catch (CloneNotSupportedException cnse) {
1366                                                System.out.println("Cloning the attribute "
1367                                                                + a.getName() + " is not supported: "
1368                                                                + cnse.getMessage());
1369                                        }
1370                                }
1371                        } else {
1372                                found = false;
1373                        }
1374                }
1375
1376                return obj;
1377        }
1378
1379        /**
1380         * removes the 'kepler:' from the port names. this tag is used to keep ptii
1381         * from throwing name duplication exceptions becuase our port metadata
1382         * Parameter has the same name as the port it describes
1383         */
1384        private String cleansePortName(String portName) {
1385                if (portName.indexOf("kepler:") != -1) {
1386                        // strip the kepler: off of the name. kepler: is there to
1387                        // prevent namedup exceptions in the moml parser
1388                        return portName.substring(7, portName.length());
1389                }
1390                return portName;
1391        }
1392
1393        /**
1394         * parse an actor to create the actorMetadata object
1395         * 
1396         *@param actor
1397         */
1398        private void parseActor() {
1399                NamedObj actor = getActor();
1400                if (actor instanceof ComponentEntity /*
1401                                                                                         * && !(actor instanceof
1402                                                                                         * TypedCompositeActor)
1403                                                                                         */) {
1404                        List<?> list = ((ComponentEntity) actor).portList();
1405                        Iterator<?> portIterator = list.iterator();
1406                        while (portIterator.hasNext()) {
1407                                Port p = (Port) portIterator.next();
1408                                PortMetadata pm = new PortMetadata();
1409
1410                                pm.name = p.getName();
1411                                
1412                                if(p instanceof TypedIOPort)
1413                                {
1414                                    pm.type = ((TypedIOPort)p).getType().toString();
1415                                }
1416                                
1417                                if(p instanceof IOPort)
1418                                {
1419                                    IOPort iop = (IOPort)p;
1420                                    
1421                                    pm.multiport = iop.isMultiport();
1422
1423                                if (iop.isInput() && iop.isOutput()) {
1424                                        pm.direction = "inputoutput";
1425    
1426                                } else if (iop.isInput()) {
1427                                        pm.direction = "input";
1428    
1429                                } else if (iop.isOutput()) {
1430                                        pm.direction = "output";
1431                                }
1432                                }
1433
1434                                pm.portClassName = p.getClassName();
1435
1436                                // get any other port attributes and copy them
1437                                List<?> portAttList = p.attributeList();
1438                                Iterator<?> portAttsIt = portAttList.iterator();
1439
1440                                while (portAttsIt.hasNext()) {
1441
1442                                        NamedObj att = (NamedObj) portAttsIt.next();
1443                                        pm.addAttribute(att);
1444
1445                                        if (isDebugging)
1446                                                log.debug("adding att: " + att.exportMoML());
1447                                }
1448
1449                                _portVector.addElement(pm);
1450                        }
1451                }
1452        }
1453
1454        /**
1455         * parse a named obj and get it's port info
1456         */
1457        private void parseNamedObj(NamedObj obj) throws InvalidMetadataException {
1458
1459                if (obj instanceof CompositeClassEntity) {
1460
1461                        // if it's a composite, look for the <port> objects instead of the
1462                        // PortProperties
1463                        Entity ent = (Entity) obj;
1464                        List<?> pList = ent.portList();
1465                        Iterator<?> portIterator = pList.iterator();
1466
1467                        while (portIterator.hasNext()) {
1468
1469                                TypedIOPort port = (TypedIOPort) portIterator.next();
1470                                PortMetadata pm = new PortMetadata();
1471
1472                                pm.name = port.getName();
1473                                pm.type = port.getType().toString();
1474                                pm.multiport = port.isMultiport();
1475
1476                                if (port.isInput()) {
1477                                        pm.direction = "input";
1478                                }
1479
1480                                if (port.isOutput()) {
1481                                        pm.direction = "output";
1482                                }
1483
1484                                if (port.isOutput() && port.isInput()) {
1485                                        pm.direction = "inputoutput";
1486                                }
1487
1488                                pm.portClassName = port.getClassName();
1489
1490                                List<?> attList = port.attributeList();
1491                                Iterator<?> listIt = attList.iterator();
1492
1493                                while (listIt.hasNext()) {
1494                                        NamedObj att = (NamedObj) listIt.next();
1495                                        pm.addAttribute(att);
1496                                }
1497
1498                                _portVector.addElement(pm);
1499
1500                        }
1501
1502                } else if (obj instanceof ComponentEntity) {
1503
1504                        List<?> list = null;
1505                        try {
1506
1507                                Class<?> cls = Class.forName("org.kepler.moml.PortAttribute");
1508                                ComponentEntity ce = (ComponentEntity) obj;
1509                                list = ce.attributeList(cls);
1510
1511                        } catch (ClassNotFoundException cnfe) {
1512                        }
1513
1514                        Iterator<?> portIterator = list.iterator();
1515
1516                        while (portIterator.hasNext()) {
1517                                PortAttribute pa = (PortAttribute) portIterator.next();
1518                                PortMetadata pm = new PortMetadata();
1519
1520                                pm.name = pa.getName();
1521                                if(pm.name == null) {
1522                                        throw new InvalidMetadataException("Port is missing name.");
1523                                }
1524                                
1525                                StringAttribute attribute = (StringAttribute) pa.getAttribute("dataType");
1526                                if(attribute == null) {
1527                                        throw new InvalidMetadataException("Port " + pm.name + " is missing dataType attribute.");
1528                                }
1529                                pm.type = attribute.getExpression();
1530                                
1531                                attribute = (StringAttribute) pa.getAttribute("isMultiport");
1532                                if(attribute == null) {
1533                                        throw new InvalidMetadataException("Port " + pm.name + " is missing isMultiport attribute.");
1534                                }
1535                                
1536                                // try parsing the boolean string
1537                                try {
1538                                        pm.multiport = Boolean.valueOf(attribute.getExpression()).booleanValue();
1539                                } catch(Throwable t) {
1540                                        throw new InvalidMetadataException("Invalid isMultiport value for port "
1541                                                        + pm.name + ": " + attribute.getExpression());
1542                                }
1543                                
1544                                attribute = (StringAttribute) pa.getAttribute("direction");
1545                                if(attribute == null) {
1546                                        throw new InvalidMetadataException("Port " + pm.name + " is missing direction attribute.");
1547                                }
1548                                pm.direction = attribute.getExpression();
1549
1550                                List<?> attList = pa.attributeList();
1551                                Iterator<?> listIt = attList.iterator();
1552
1553                                while (listIt.hasNext()) {
1554                                        NamedObj att = (NamedObj) listIt.next();
1555
1556                                        if (!att.getName().equals("dataType")
1557                                                        && !att.getName().equals("isMultiport")
1558                                                        && !att.getName().equals("direction")) {
1559
1560                                                if (isDebugging)
1561                                                        log.debug("adding att: " + att.exportMoML());
1562                                                pm.addAttribute(att);
1563                                        }
1564                                }
1565
1566                                _portVector.addElement(pm);
1567                        }
1568                }
1569        }
1570
1571        /**
1572         * look for a moml class and try to instantiate it
1573         * 
1574         * @param actorName
1575         * @param className
1576         * @param actorMetadataMoml
1577         * @return
1578         */
1579        private NamedObj lookForMoml(String actorName, String className,
1580                        NamedObj actorMetadataMoml) throws Exception {
1581                if (isDebugging) log.debug("lookForMoml");
1582
1583                if (_internalClassName.equals("org.kepler.moml.CompositeClassEntity")) {
1584                        // This is a total hack, but I cannot get the
1585                        // CompositeActors to clone correctly, so this try statement
1586                        // basically clones them manually. It works so i'm leaving
1587                        // it for now.
1588                        try {
1589                                StringBuffer sb = new StringBuffer();
1590                                // sb.append("<class name=\"" + actorName +
1591                                // "\" extends=\"" + className + "\">");
1592                                sb.append("<entity name=\"" + actorName + "\" class=\""
1593                                                + className + "\">");
1594
1595                                // get attributes and clone them over to the new obj
1596                                CompositeClassEntity cce = (CompositeClassEntity) actorMetadataMoml;
1597                                Iterator<?> attItt = cce.attributeList().iterator();
1598
1599                                while (attItt.hasNext()) {
1600                                        Attribute a = (Attribute) attItt.next();
1601                                        sb.append(a.exportMoML());
1602                                }
1603
1604                                // get entities and clone them over to the new obj
1605
1606                                Iterator<?> entItt = cce.entityList().iterator();
1607                                while (entItt.hasNext()) {
1608                                        ComponentEntity ent = (ComponentEntity) entItt.next();
1609                                        sb.append(ent.exportMoML());
1610                                }
1611
1612                                // get ports and clone them over to the new obj
1613                                Iterator<?> portItt = cce.portList().iterator();
1614                                while (portItt.hasNext()) {
1615                                        Port p = (Port) portItt.next();
1616                                        sb.append(p.exportMoML());
1617                                }
1618
1619                                // get relations and clone them over to the new obj
1620                                TypedCompositeActor tca = (TypedCompositeActor) actorMetadataMoml;
1621                                Iterator<?> relationItt = tca.relationList().iterator();
1622                                while (relationItt.hasNext()) {
1623                                        ComponentRelation r = (ComponentRelation) relationItt
1624                                                        .next();
1625                                        sb.append(r.exportMoML());
1626                                }
1627
1628                                sb.append(_links);
1629                                // sb.append("</class>");
1630                                sb.append("</entity>");
1631
1632                                Workspace w = actorMetadataMoml.workspace();
1633
1634                                if (isDebugging)
1635                                        log.debug("**** MoMLParser ****");
1636
1637                                MoMLParser parser = new MoMLParser(w);
1638                                parser.reset();
1639                                NamedObj obj = parser.parse(sb.toString());
1640                                return obj;
1641                        } catch (Exception exc) {
1642                                System.out.println("error creating compositeClassEntity: "
1643                                                + exc.getMessage());
1644                                exc.printStackTrace();
1645                                throw exc;
1646                        }
1647                } else {
1648                    
1649                    // see if the internal class name is a subclass of composite actor
1650                    Class<?> clazz = Class.forName(_internalClassName);
1651                    Class<?> compositeActorClass = Class.forName("ptolemy.actor.TypedCompositeActor");
1652                    if(compositeActorClass.isAssignableFrom(clazz)) {
1653                        
1654                        // parse the moml in the actor metadata
1655                MoMLParser parser = new MoMLParser(actorMetadataMoml.workspace());
1656                parser.reset();
1657                NamedObj obj = parser.parse(actorMetadataMoml.exportMoML());
1658                return obj;                     
1659                        
1660                    } else {
1661                        // ptolemy.kernel.ComponentEntity
1662                        ComponentEntity actor = parseMoMLFile(className);
1663                        if (isDebugging) {
1664                                log.debug("returning " + actor.getName());
1665                        }
1666                        return (TypedCompositeActor) actor;
1667                    }
1668                }
1669
1670        }
1671
1672        /**
1673         * get the actor class and instantiate it to a NamedObj and return it
1674         */
1675        private NamedObj getActorClass(String className, String actorName,
1676                        NamedObj actorMetadataMoml) {
1677
1678                if (isDebugging && actorMetadataMoml != null) {
1679                        log.debug("getActorClass(" + className + "," + actorName + ","
1680                                        + actorMetadataMoml.getName() + ")");
1681                }
1682
1683                // try to get the actor class and instantiate it
1684                try {
1685                        
1686                        TypedAtomicActor actor;
1687                        Class<?> actorClass = Class.forName(className);
1688                        CompositeEntity ce = new CompositeEntity();
1689                        Object[] args = { ce, actorName };
1690                        actor = (TypedAtomicActor) createInstance(actorClass, args);
1691
1692                        // call the metadata handlers
1693                        for (int i = 0; i < _metadataHandlerVector.size(); i++) {
1694
1695                                Object o = _metadataHandlerVector.elementAt(i);
1696                                MetadataHandler handler = (MetadataHandler) o;
1697                                handler.handleMetadata(actor);
1698                        }
1699
1700                        return actor;
1701                        
1702                } catch (Exception e) {
1703                        if (isDebugging) {
1704                                log.debug(e.toString());
1705                                log.debug(_internalClassName);
1706                        }
1707                        
1708                        NamedObj secTry;
1709                        try {
1710                                
1711                                secTry = lookForMoml(actorName, className, actorMetadataMoml);
1712                                return secTry;
1713
1714                        } catch (Exception ee) {
1715                                if (isDebugging)
1716                                        log.debug(ee.toString());
1717                                
1718                                NamedObj thirdTry;
1719                                try {
1720
1721                                        thirdTry = handleNonEntityDirectors(actorName, className, 
1722                                                        actorMetadataMoml);
1723                                        return thirdTry;
1724
1725                                } catch (Exception eee) {
1726                                        
1727                                        if (isDebugging)
1728                                                log.debug(eee.toString());
1729
1730                                        NamedObj fourthTry;
1731                                        try {
1732
1733                                                fourthTry = handleMiscAtt(actorName, className, 
1734                                                                actorMetadataMoml);
1735                                                return fourthTry;
1736
1737                                        } catch (Exception eeee) {
1738                                                
1739                                                printFinalException(eeee,className);
1740                                                return null;
1741                                        }
1742                                }
1743                        }
1744                }
1745        }
1746        
1747        /**
1748         * Helper method.
1749         * @param eeee
1750         * @param className
1751         */
1752        private void printFinalException(Exception eeee,String className) {
1753                System.out.println("The class name you entered was either not "
1754                                + "found in classpath or could not be instantiated:");
1755                System.out.println(className);
1756                System.out.println("Note that this class must be in the "
1757                                + "classpath from which you launched this program.");
1758                String msg = eeee.getMessage();
1759                if (msg != null) {
1760                        System.out.println(msg);
1761                }
1762
1763        }
1764
1765        /**
1766         * Todo: What is this doing?
1767         * @param className
1768         * @param actorName
1769         * @param actorMetadataMoml
1770         * @return
1771         * @throws Exception
1772         */
1773        private NamedObj handleMiscAtt(String actorName, String className, 
1774                        NamedObj actorMetadataMoml) throws Exception {
1775
1776                Attribute att;
1777                Class<?> attClass = Class.forName(className);
1778                // NOTE: place the attribute inside a TypedCompositeActor instead
1779                // of a CompositeEntity since PortParameter requires the container
1780                // to implement TypedActor.
1781                Object[] args = { new TypedCompositeActor(), actorName };
1782                att = (Attribute) createInstance(attClass, args);
1783                return att;
1784        }
1785
1786        /**
1787         * This handles directors which are not entities, but attributes
1788         * 
1789         * @param className
1790         * @param actorName
1791         * @param actorMetadataMoml
1792         * @return
1793         * @throws Exception
1794         */
1795        private NamedObj handleNonEntityDirectors(String actorName,
1796                        String className, NamedObj actorMetadataMoml) throws Exception {
1797
1798                Director director;
1799                Class<?> directorClass = Class.forName(className);
1800                Object[] args = { new CompositeEntity(), actorName };
1801                director = (Director) createInstance(directorClass, args);
1802                return director;
1803        }
1804
1805        /**
1806         * add all of the attributes with the exception of the kepler attributes
1807         * (which should already be in the metadata) to the AM object.
1808         * 
1809         * @param obj
1810         *            the NamedObj to get the attributes from.
1811         */
1812        private void addAllAttributes() {
1813                NamedObj obj = getActor();
1814                if (obj != null && obj.attributeList() != null) {
1815
1816                        List<?> attList = obj.attributeList();
1817                        Iterator<?> i = attList.iterator();
1818
1819                        while (i.hasNext()) {
1820                                Attribute a = (Attribute) i.next();
1821                                String name = a.getName();
1822                                if (!name.equals(NamedObjId.NAME) && !name.equals("class")
1823                                                && !name.equals("KeplerDocumentation")
1824                                                && name.indexOf("dependency") == -1) {
1825                                        addAttribute(a);
1826                                }
1827
1828                        }
1829                }
1830        }
1831        
1832        private void removeLinks() {
1833                NamedObj obj = getActor();
1834                if (obj == null) return;
1835        }
1836
1837        /**
1838         * add all of the relations
1839         * 
1840         * @param obj
1841         *            the NamedObj to get the attributes from.
1842         */
1843        private void addAllRelations() {
1844                NamedObj obj = getActor();
1845                if (obj == null) return;
1846                
1847                if (obj instanceof TypedCompositeActor) {
1848                        TypedCompositeActor tca = (TypedCompositeActor) obj;
1849                        List<?> relList = tca.relationList();
1850                        if (relList != null) {
1851                        
1852                                Iterator<?> i = relList.iterator();
1853                                while (i.hasNext()) {
1854                                        ComponentRelation r = (ComponentRelation) i.next();
1855                                        addRelation(r);
1856                                }
1857                        }
1858                }
1859        }
1860
1861        /**
1862         * search the classpath for a specific class and return the file. In the
1863         * tradition of ptolemy, this will also search for moml files with a class
1864         * definition. this is required for composite actors.
1865         * 
1866         * @param className
1867         *            the name of the class to search for
1868         * @param workDir
1869         *            the directory where temp files can be created
1870         */
1871        protected File searchClasspath(String className)
1872                        throws FileNotFoundException {
1873                
1874                // separate the class name from the package path
1875                String actualClassName = className.substring(
1876                                className.lastIndexOf(".") + 1, className.length());
1877                String packagePath = className.substring(0, className.lastIndexOf("."));
1878                String[] packagePathStruct = packagePath.split("\\.");
1879
1880                // get the classpath so we can search for the class files
1881                String classpath = System.getProperty("java.class.path");
1882                String sep = System.getProperty("path.separator");
1883                StringTokenizer st = new StringTokenizer(classpath, sep);
1884                
1885                while (st.hasMoreTokens()) {
1886                        String path = st.nextToken();
1887                        File pathDir = new File(path);
1888
1889                        if (pathDir.isDirectory()) {
1890                                // search the directory for the file
1891
1892                                if (matchDirectoryPath(pathDir, packagePathStruct, 0)) {
1893                                        // now we found a candidate...see if the class is in there
1894                                        File classDir = new File(pathDir.getAbsolutePath()
1895                                                        + File.separator
1896                                                        + packagePath.replace('.', File.separator
1897                                                                        .toCharArray()[0]));
1898                                        File[] classDirFiles = classDir.listFiles();
1899                                        for (int i = 0; i < classDirFiles.length; i++) {
1900
1901                                                String dirFileName = classDirFiles[i].getName();
1902
1903                                                if (dirFileName.indexOf(".") != -1) {
1904                                                        String extension = dirFileName.substring(
1905                                                                        dirFileName.lastIndexOf("."), dirFileName
1906                                                                                        .length());
1907                                                        String prefix = dirFileName.substring(0,
1908                                                                        dirFileName.lastIndexOf("."));
1909                                                        if (actualClassName.equals(prefix)
1910                                                                        && (extension.equals(".class") || extension
1911                                                                                        .equals(".xml"))) {
1912                                                                // search for xml or class files
1913                                                                return classDirFiles[i];
1914                                                        }
1915                                                }
1916                                        }
1917                                }
1918                        } else if (pathDir.isFile()) {
1919                                // search a jar file for the file. if it's not a jar file,
1920                                // ignore it
1921                                try {
1922                                        String entryName = className.replace('.', '/') + ".class";
1923                                        JarFile jarFile = null;
1924                                        try {
1925                                            jarFile = new JarFile(pathDir);
1926                                        // this looks for a class file
1927                                        JarEntry entry = jarFile.getJarEntry(entryName);
1928                                        if (entry != null) {
1929                                                // get the class file from the jar and return it
1930                                                return pathDir;
1931                                        } else {
1932                                                // look for the xml file instead
1933                                                entryName = className.replace('.', '/') + ".xml";
1934                                                entry = jarFile.getJarEntry(entryName);
1935                                                if (entry != null) {
1936                                                        return pathDir;
1937                                                }
1938                                        }
1939                                        } finally {
1940                                            if(jarFile != null) {
1941                                                jarFile.close();
1942                                            }
1943                                        }
1944                                } catch (Exception e) {
1945                                        // keep going if this isn't a jar file
1946                                        continue;
1947                                }
1948                        }
1949                }
1950                throw new FileNotFoundException("Cannot find the specified class "
1951                                + "file in the classpath.");
1952        }
1953
1954        /**
1955         * locates a directory based on an array of paths to look for. for instance,
1956         * if you are searching for org/kepler/kar searchForMe would be {org,
1957         * kepler, kar}. dir is where the search starts. Index should start out as
1958         * 0.
1959         */
1960        private boolean matchDirectoryPath(File dir, String[] searchForMe, int index) {
1961                File[] dirContents = dir.listFiles();
1962                for (int i = 0; i < dirContents.length; i++) {
1963                        if (dirContents[i].getName().equals(searchForMe[index])) {
1964                                if (index < searchForMe.length - 1) {
1965                                        if (index < searchForMe.length) {
1966                                                return matchDirectoryPath(dirContents[i], searchForMe,
1967                                                                ++index);
1968                                        } else {
1969                                                return false;
1970                                        }
1971                                } else {
1972                                        return true;
1973                                }
1974                        }
1975                }
1976                return false;
1977        }
1978
1979        /**
1980         * try to locate and parse a moml file as a class
1981         */
1982        protected ComponentEntity parseMoMLFile(String className) throws Exception {
1983                if (isDebugging)
1984                        log.debug("parseMoMLFile(" + className + ")");
1985
1986        JarFile jarFile = null;
1987        InputStream xmlStream = null;
1988                try {
1989                // first we need to find the file and read it
1990                File classFile = searchClasspath(className);
1991                StringWriter sw = new StringWriter();
1992                if (classFile.getName().endsWith(".jar")) {
1993                        jarFile = new JarFile(classFile);
1994                        ZipEntry entry = jarFile.getEntry(className.replace('.', '/')
1995                                        + ".xml");
1996                        xmlStream = jarFile.getInputStream(entry);
1997                } else {
1998                        xmlStream = new FileInputStream(classFile);
1999                }
2000    
2001                byte[] b = new byte[1024];
2002                int numread = xmlStream.read(b, 0, 1024);
2003                while (numread != -1) {
2004                        String s = new String(b, 0, numread);
2005                        sw.write(s);
2006                        numread = xmlStream.read(b, 0, 1024);
2007                }
2008                sw.flush();
2009                // get the moml document
2010                String xmlDoc = sw.toString();
2011                sw.close();
2012
2013                if (isDebugging)
2014                        log.debug("**** MoMLParser ****");
2015    
2016                // use the moml parser to parse the doc
2017                MoMLParser parser = new MoMLParser();
2018                parser.reset();
2019    
2020                // System.out.println("processing " + className);
2021                NamedObj obj = parser.parse(xmlDoc);
2022                return (ComponentEntity) obj;
2023                } finally {
2024            if(jarFile != null) {
2025                jarFile.close();
2026            }
2027            if(xmlStream != null) {
2028                xmlStream.close();
2029            }
2030                }
2031        }
2032
2033        /**
2034         * createInstance. creates an instance of a class object. taken from
2035         * ptolemy's MomlParser class. modified for this application.
2036         * 
2037         * @param newClass
2038         *@param arguments
2039         *@return TypedAtomicActor
2040         *@exception Exception
2041         */
2042        public static NamedObj createInstance(Class<?> newClass, Object[] arguments)
2043                        throws Exception {
2044                if (isDebugging)
2045                        log.debug("createInstance(" + newClass + "," + arguments + ")");
2046                Constructor<?>[] constructors = newClass.getConstructors();
2047                for (int i = 0; i < constructors.length; i++) {
2048                        Constructor<?> constructor = constructors[i];
2049                        Class<?>[] parameterTypes = constructor.getParameterTypes();
2050
2051                        for (int j = 0; j < parameterTypes.length; j++) {
2052                                Class<?> c = parameterTypes[j];
2053                                if (isDebugging) 
2054                                        log.debug(c.getName());
2055                        }
2056
2057                        if (parameterTypes.length != arguments.length) {
2058                                continue;
2059                        }
2060
2061                        boolean match = true;
2062
2063                        for (int j = 0; j < parameterTypes.length; j++) {
2064                                if (!(parameterTypes[j].isInstance(arguments[j]))) {
2065                                        match = false;
2066                                        break;
2067                                }
2068                        }
2069
2070                        if (match) {
2071                                NamedObj newEntity = (NamedObj) constructor
2072                                                .newInstance(arguments);
2073                                return newEntity;
2074                        }
2075                }
2076
2077                // If we get here, then there is no matching constructor.
2078                // Generate a StringBuffer containing what we were looking for.
2079                StringBuffer argumentBuffer = new StringBuffer();
2080
2081                for (int i = 0; i < arguments.length; i++) {
2082                        argumentBuffer.append(arguments[i].getClass() + " = \""
2083                                        + arguments[i].toString() + "\"");
2084
2085                        if (i < (arguments.length - 1)) {
2086                                argumentBuffer.append(", ");
2087                        }
2088                }
2089
2090                throw new Exception("Cannot find a suitable constructor ("
2091                                + arguments.length + " args) (" + argumentBuffer + ") for '"
2092                                + newClass.getName() + "'");
2093        }
2094
2095        /**
2096         * This method is just a helper debugging method to write out the object
2097         * moml to a file in a specified location on disk, the cache dir.
2098         * 
2099         * @param obj
2100         * @param filename
2101         */
2102        private void writeDebugMomlFor(NamedObj obj, String filename) {
2103                String momlExport = obj.exportMoML();
2104
2105                DotKeplerManager dkm = DotKeplerManager.getInstance();
2106                File f = new File(dkm.getCacheDir(), filename);
2107                FileWriter fw;
2108                try {
2109                        fw = new FileWriter(f);
2110                        fw.write(momlExport, 0, momlExport.length());
2111                        fw.flush();
2112                        fw.close();
2113                        System.out.println("done exporting debug moml: " + f.toString());
2114                } catch (IOException e) {
2115                        e.printStackTrace();
2116                }
2117        }
2118
2119        /**
2120         * metadata object for a classed property
2121         */
2122        private static class ClassedProperty implements Serializable {
2123                public String name = "";
2124                public String value = "";
2125                public String className = "";
2126                public Integer iterator = null;
2127
2128                /**
2129                 * constructor
2130                 */
2131                public ClassedProperty(String name, String value, String className) {
2132                        this.name = name;
2133                        this.value = value;
2134                        this.className = className;
2135                }
2136
2137                /**
2138                 * adds an integer to the end of the name of the property if there is
2139                 * more than one of these properties. for instance: semanticType0,
2140                 * semanticType1, etc.
2141                 * 
2142                 * @param int i the number to add to the name.
2143                 */
2144                public void addNameIterator(int i) {
2145                        iterator = Integer.valueOf(i);
2146                }
2147
2148                /**
2149                 * create the xml rep of the ClassedProperty
2150                 */
2151                public String toString() {
2152                        if (iterator == null) {
2153                                return "<property name=\"" + name + "\" value=\"" + value
2154                                                + "\" class=\"" + className + "\"/>";
2155                        } else {
2156                                int itt = iterator.intValue();
2157                                return "<property name=\"" + name + itt + "\" value=\"" + value
2158                                                + "\" class=\"" + className + "\"/>";
2159                        }
2160                }
2161        }
2162
2163        /**
2164         * metadata object that represents a port
2165         */
2166        private static class PortMetadata implements Serializable {
2167                public String name = "";
2168                public String direction = "";
2169                public String type = "";
2170                public boolean multiport = false;
2171                public Vector<NamedObj> attributes = new Vector<NamedObj>();
2172                
2173                /** The class name of the port, e.g., ptolemy.actor.TypedIOPort */
2174                public String portClassName;
2175
2176                public void addAttribute(NamedObj att) {
2177                        attributes.addElement(att);
2178                }
2179
2180                /**
2181                 * return the moml xml rep of the port
2182                 * 
2183                 * */
2184                public String toString() {
2185                        StringBuffer sb = new StringBuffer();
2186
2187                        if (name.indexOf("kepler:") != -1) {
2188                                sb.append("<property name=\"" + name
2189                                                + "\" class=\"org.kepler.moml.PortAttribute\">\n");
2190                        } else {
2191                                sb.append("<property name=\"kepler:" + name
2192                                                + "\" class=\"org.kepler.moml.PortAttribute\">\n");
2193                        }
2194                        sb.append("  <property name=\"direction\" value=\"" + direction
2195                                        + "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
2196                        sb.append("  <property name=\"dataType\" value=\"" + type
2197                                        + "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
2198                        sb.append("  <property name=\"isMultiport\" value=\"" + multiport
2199                                        + "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
2200                        for (int i = 0; i < attributes.size(); i++) {
2201                                // System.out.println("appending port attribute: " +
2202                                // ((NamedObj)attributes.elementAt(i)).exportMoML());
2203                                sb.append("  "
2204                                                + ((NamedObj) attributes.elementAt(i)).exportMoML());
2205                        }
2206                        sb.append("</property>\n");
2207                        /*
2208                         * sb.append("<port name=\"" + name +
2209                         * "\" class=\"ptolemy.actor.IOPort\">\n");
2210                         * sb.append("  <property name=\"direction\" value=\"" + direction +
2211                         * "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
2212                         * sb.append("  <property name=\"dataType\" value=\"" + type +
2213                         * "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
2214                         * sb.append("  <property name=\"isMultiport\" value=\"" + multiport
2215                         * + "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
2216                         * sb.append("</port>\n");
2217                         */
2218                        return sb.toString();
2219                }
2220
2221                public String toMoMLString() {
2222                        StringBuffer sb = new StringBuffer();
2223                        String dispName = name;
2224                        if (name.indexOf("kepler:") != -1) {
2225                                dispName = name.substring(8, name.length());
2226                        }
2227
2228                String escapedDispName = StringUtilities.escapeForXML(dispName);
2229                                
2230            sb.append("<port name=\"" + escapedDispName + "\" class=\""
2231                    + portClassName + "\">\n");
2232                                
2233                        if (direction.equals("input")) {
2234                                sb.append("  <property name=\"input\"/>\n");
2235                        }
2236                        if (direction.equals("output")) {
2237                                sb.append("  <property name=\"output\"/>\n");
2238                        }
2239                        if (direction.equals("inputoutput")) {
2240                                sb.append("  <property name=\"output\"/>\n");
2241                                sb.append("  <property name=\"input\"/>\n");
2242                        }
2243                        // added by Dan Higgins April 2007
2244                        sb.append("  <property name=\"dataType\" value=\"" + type
2245                                        + "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
2246                        sb.append("  <property name=\"isMultiport\" value=\"" + multiport
2247                                        + "\" class=\"ptolemy.kernel.util.StringAttribute\"/>\n");
2248                        for (int i = 0; i < attributes.size(); i++) {
2249                                // System.out.println("appending port attribute: " +
2250                                // ((NamedObj)attributes.elementAt(i)).exportMoML());
2251                                sb.append("  "
2252                                                + ((NamedObj) attributes.elementAt(i)).exportMoML());
2253                        }
2254                        // end addition by Dan Higgins April 2007
2255                        sb.append("</port>\n");
2256                        return sb.toString();
2257                }
2258        }
2259}