001/* A token that contains a set of label/token pairs.
002
003 Copyright (c) 2003-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027
028 */
029package ptolemy.data;
030
031import org.w3c.dom.Document;
032
033import ptolemy.data.expr.XMLParser;
034import ptolemy.data.type.BaseType;
035import ptolemy.data.type.Type;
036import ptolemy.data.type.TypeLattice;
037import ptolemy.graph.CPO;
038import ptolemy.kernel.util.IllegalActionException;
039
040///////////////////////////////////////////////////////////////////
041//// XmlToken
042
043/**
044 A token that contains a xml document.
045
046 Currently, no operations between function tokens (add, multiply, etc.)
047 are supported.
048
049 @author Yang Zhao
050 @version $Id$
051 @since Ptolemy II 4.0
052 @Pt.ProposedRating Red (neuendor)
053 @Pt.AcceptedRating Red (cxh)
054 */
055public class XMLToken extends Token {
056    /** Construct an empty token.
057     */
058    public XMLToken() {
059        super();
060        _toString = "";
061    }
062
063    /** Construct an XmlToken from the specified string.
064     *  @param init The initialization string.
065     *  @exception Exception If the string is not parsable.
066     */
067    public XMLToken(String init) throws Exception {
068        XMLParser parser = new XMLParser();
069        _doc = parser.parser(init);
070        _toString = init;
071    }
072
073    ///////////////////////////////////////////////////////////////////
074    ////                         public methods                    ////
075
076    /** Convert the specified token into an instance of XMLToken.
077     *  If the specified token is not an instance of XMLToken,
078     *  an exception is thrown.
079     *  @param token The token to be converted to a XMLToken.
080     *  @return A XMLToken.
081     *  @exception IllegalActionException If the conversion
082     *   cannot be carried out.
083     */
084    public static XMLToken convert(Token token) throws IllegalActionException {
085        if (token instanceof XMLToken) {
086            return (XMLToken) token;
087        }
088
089        throw new IllegalActionException(
090                notSupportedConversionMessage(token, "xmltoken"));
091    }
092
093    /** Return the dom document parsed from the xml string.
094     *  @return A Document.
095     */
096    public Document getDomTree() {
097        return _doc;
098    }
099
100    /** Return true if the argument is an instance of XMLToken with the
101     *  same value.
102     *  @param object An instance of Object.
103     *  @return True if the argument is an IntToken with the same
104     *  value. If either this object or the argument is nil, return
105     *  false.
106     */
107    @Override
108    public boolean equals(Object object) {
109        // See http://www.technofundo.com/tech/java/equalhash.html
110        if (object == this) {
111            return true;
112        }
113        if (object == null) {
114            return false;
115        }
116        // This test rules out subclasses.
117        if (object.getClass() != getClass()) {
118            return false;
119        }
120
121        if (isNil() || ((XMLToken) object).isNil()) {
122            return false;
123        }
124
125        if (((XMLToken) object).toString().equals(_toString)) {
126            return true;
127        }
128
129        return false;
130    }
131
132    /** Return the hash code for the XMLToken object. If two XMLToken
133     *  objects contains the same String then they have the same
134     *  hashcode.
135     *  @return The hash code for this XMLToken object.
136     */
137    @Override
138    public int hashCode() {
139        // See http://www.technofundo.com/tech/java/equalhash.html
140        int hashCode = 27;
141        if (_toString != null) {
142            hashCode = 31 * hashCode + _toString.hashCode();
143        }
144        return hashCode;
145    }
146
147    /** Test that the value of this token is close to the first argument,
148     *  where "close" means that the distance between them is less than
149     *  or equal to the second argument.  This method only makes sense
150     *  for tokens where the distance between them is reasonably
151     *  represented as a double. If the argument token is not of
152     *  the same type as this token, then either this token or the
153     *  argument will be converted, if possible, to the type of the other.
154     *  <p>
155     *  Subclasses should not
156     *  generally override this method, but override the protected
157     *  _isCloseTo() method to ensure that type conversion is performed
158     *  consistently.
159     *  @param token The token to test closeness of this token with.
160     *  @param epsilon The value that we use to determine whether two
161     *   tokens are close.
162     *  @return A boolean token that contains the value true if the
163     *   value and units of this token are close to those of the
164     *   argument token.
165     *  @exception IllegalActionException If the argument token and
166     *   this token are of incomparable types, or the operation does
167     *   not make sense for the given types.
168     */
169    @Override
170    public final BooleanToken isCloseTo(Token token, double epsilon)
171            throws IllegalActionException {
172        // FIXME: This is copied from AbstractConvertibleToken.
173
174        // Note that if we had absolute(), subtraction() and islessThan()
175        // we could perhaps define this method for all tokens.
176        int typeInfo = TypeLattice.compare(getType(), token);
177
178        if (typeInfo == CPO.SAME) {
179            return _isCloseTo(token, epsilon);
180        } else if (typeInfo == CPO.HIGHER) {
181            AbstractConvertibleToken convertedArgument = (AbstractConvertibleToken) getType()
182                    .convert(token);
183
184            try {
185                BooleanToken result = _isCloseTo(convertedArgument, epsilon);
186                return result;
187            } catch (IllegalActionException ex) {
188                // If the type-specific operation fails, then create a
189                // better error message that has the types of the
190                // arguments that were passed in.
191                throw new IllegalActionException(null, ex,
192                        notSupportedMessage("isCloseTo", this, token));
193            }
194        } else if (typeInfo == CPO.LOWER) {
195            return token.isCloseTo(this, epsilon);
196        } else {
197            throw new IllegalActionException(
198                    notSupportedIncomparableMessage("isCloseTo", this, token));
199        }
200    }
201
202    /** Return the type of this token.
203     *  @return BaseType.XMLTOKEN.
204     */
205    @Override
206    public Type getType() {
207        return BaseType.XMLTOKEN;
208    }
209
210    /** Return the value of this Token as a string.
211     *  @return A String.
212     */
213    @Override
214    public String toString() {
215        return _toString;
216    }
217
218    ///////////////////////////////////////////////////////////////////
219    ////                         protected methods                 ////
220
221    /** Test for closeness of the values of this Token and the argument
222     *  Token.  It is assumed that the type of the argument is
223     *  an XMLToken.
224     *  @param rightArgument The token to add to this token.
225     *  @param epsilon The value that we use to determine whether two
226     *  tokens are close.  This parameter is ignored by this class.
227     *  @return A BooleanToken containing the result.
228     *  @exception IllegalActionException If this method is not
229     *  supported by the derived class.
230     */
231    protected BooleanToken _isCloseTo(Token rightArgument, double epsilon)
232            throws IllegalActionException {
233        return _isEqualTo(rightArgument);
234    }
235
236    /** Test for equality of the values of this Token and the argument
237     *  Token.  It is assumed that the type of the argument is
238     *  XMLToken.
239     *  @param rightArgument The token to add to this token.
240     *  @return A BooleanToken containing the result.
241     *  @exception IllegalActionException If this method is not
242     *  supported by the derived class.
243     */
244    protected BooleanToken _isEqualTo(Token rightArgument)
245            throws IllegalActionException {
246        XMLToken convertedArgument = (XMLToken) rightArgument;
247        return BooleanToken.getInstance(
248                toString().compareTo(convertedArgument.toString()) == 0);
249    }
250
251    ///////////////////////////////////////////////////////////////////
252    ////                         private variables                 ////
253    private Document _doc;
254
255    private String _toString;
256}