001/*
002 * Copyright (c) 2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
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.ROADnet;
031
032import java.lang.reflect.Array;
033import java.lang.reflect.Field;
034
035import ptolemy.actor.lib.Transformer;
036import ptolemy.data.ObjectToken;
037import ptolemy.data.RecordToken;
038import ptolemy.data.Token;
039import ptolemy.data.type.BaseType;
040import ptolemy.kernel.CompositeEntity;
041import ptolemy.kernel.util.IllegalActionException;
042import ptolemy.kernel.util.NameDuplicationException;
043
044/**
045 * Ptolemy actor to produce from an ObjectToken a RecordToken, with record
046 * entries corresponding to fields within the object carried by the ObjectToken.
047 * This actor was originally written to eliminate the need for special
048 * field-accessor actors for each class transported with ObjectToken; it seems
049 * like a logical enough thing to do, as an Object is pretty much a record where
050 * names can map to other Objects (fields) or to function closures (methods).
051 * This actor ignores methods completely.
052 * 
053 * <p>
054 * <img src="http://mercali.ucsd.edu/~tobin/OrbObjectToRecordDemo.png"/>
055 * </p>
056 * 
057 * @author Tobin Fricke (tobin@splorg.org), University of California
058 * @version $Id: ObjectToRecord.java 24234 2010-05-06 05:21:26Z welker $
059 * @see RecordToObject
060 * @Pt.ProposedRating Red (tobin)
061 */
062
063public class ObjectToRecord extends Transformer {
064
065        /**
066         * @param container
067         *            The container.
068         * @param name
069         *            The name of this actor.
070         * @exception IllegalActionException
071         *                If the actor cannot be contained by the proposed
072         *                container.
073         * @exception NameDuplicationException
074         *                If the container already has an actor with this name.
075         */
076
077        public ObjectToRecord(CompositeEntity container, String name)
078                        throws NameDuplicationException, IllegalActionException {
079                super(container, name);
080
081                input.setTypeEquals(BaseType.OBJECT);
082                // output.setTypeAtLeast(new RecordType(new String[0], new Type[0])); //
083                // FIXME
084        }
085
086        public boolean prefire() throws IllegalActionException {
087                return (input.hasToken(0) && super.prefire());
088        }
089
090        /**
091         * Accept an ObjectToken from the input and produce a corresponding
092         * RecordToken on the output.
093         */
094
095        public void fire() throws IllegalActionException {
096                super.fire();
097
098                Object o = ((ObjectToken) (input.get(0))).getValue();
099                Class c = o.getClass();
100                Field[] fields = c.getFields();
101                int nFields = Array.getLength(fields);
102
103                String[] labels = new String[nFields];
104                ObjectToken[] values = new ObjectToken[nFields];
105
106                for (int i = 0; i < nFields; i++) {
107                        Field f = (Field) (Array.get(fields, i));
108                        labels[i] = f.getName();
109                        try {
110                                /*
111                                 * Here there is room to do something smart, like convert
112                                 * java.lang.String objects into StringTokens.
113                                 */
114                                values[i] = new ObjectToken(f.get(o));
115                        } catch (IllegalAccessException e) {
116                                values[i] = new ObjectToken(null); // not the best approach
117                        }
118                }
119
120                /*
121                 * It might be useful to either include the classname as a field in the
122                 * record (problematic due to possible name collission), as a separate
123                 * token, or even in a higher level of recordToken wrapping.
124                 */
125
126                Token r = new RecordToken(labels, values);
127                output.broadcast(r);
128        }
129
130}