001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.vmd.api.model;
042:
043: /**
044: * This immutable class represents a type of objects/components in the model. Each object/component has it unique type id.
045: * It is similar to "Class.getName ()" in J2SE.
046: * <p>
047: * It holds information about kind, string, and dimension. Kind describes whether it is a primitive (any type that is NOT taken
048: * as a component in the model), component (any type that IS taken as a component in the model), or an enum.
049: * The string is any identification string of the type indepentant on kind and dimension.
050: * The dimension is dimension of type similar to arrays in J2SE.
051: * <p>
052: * This class could be presented as a String too because it has unique 1-1 mapping with it.
053: *
054: * @author David Kaspar
055: */
056: public final class TypeID {
057:
058: private static final char PRIMITIVE_ID = 'P'; // NOI18N
059: private static final char ENUM_ID = 'E'; // NOI18N
060: private static final char COMPONENT_ID = 'C'; // NOI18N
061:
062: /**
063: * The type id kind.
064: */
065: public enum Kind {
066:
067: /**
068: * Any type that is NOT taken as a component in the model.
069: */
070: PRIMITIVE,
071: /**
072: * An enum type.
073: */
074: ENUM,
075:
076: /**
077: * Any type that IS taken as a component in the model.
078: */
079: COMPONENT
080: }
081:
082: private String encoded;
083:
084: private Kind kind;
085: private String string;
086: private int dimension;
087:
088: private TypeID(String string) {
089: decode(string);
090: this .encoded = string;
091: }
092:
093: /**
094: * Creates a new instance by specifying kind and string. Dimension is 0 = no array.
095: * @param kind the kind
096: * @param string the string
097: */
098: public TypeID(Kind kind, String string) {
099: this (kind, string, 0);
100: }
101:
102: /**
103: * Creates a new instance by specifying kind, string, dimension.
104: * @param kind the kind
105: * @param string the string
106: * @param dimension the dimension (0 = no array, 1 = one-dimensional array, ...)
107: */
108: public TypeID(Kind kind, String string, int dimension) {
109: this .kind = kind;
110: this .string = string;
111: this .dimension = dimension;
112: encoded = encode();
113: }
114:
115: /**
116: * Returns a kind.
117: * @return the kind
118: */
119: public Kind getKind() {
120: return kind;
121: }
122:
123: /**
124: * Returns an identification string.
125: * @return the string
126: */
127: public String getString() {
128: return string;
129: }
130:
131: /**
132: * Return a type dimension.
133: * @return the dimension
134: */
135: public int getDimension() {
136: return dimension;
137: }
138:
139: /**
140: * Returns encoded string representation of the type id.
141: * @return the encoded string
142: */
143: public String getEncoded() {
144: return encoded;
145: }
146:
147: private void decode(String string) {
148: assert string != null && string.length() >= 1;
149: int pos = 0;
150:
151: dimension = 0;
152: for (;;) {
153: assert pos < string.length();
154: char c = string.charAt(pos);
155: if (c < '0' || c > '9') // NOI18N
156: break;
157: dimension = (dimension * 10) + (c - '0'); // NOI18N
158: pos++;
159: }
160:
161: assert pos < string.length();
162: switch (string.charAt(pos)) {
163: case PRIMITIVE_ID:
164: kind = Kind.PRIMITIVE;
165: break;
166: case ENUM_ID:
167: kind = Kind.ENUM;
168: break;
169: case COMPONENT_ID:
170: kind = Kind.COMPONENT;
171: }
172: pos++;
173:
174: this .string = string.substring(pos);
175: }
176:
177: private String encode() {
178: StringBuilder buffer = new StringBuilder();
179: if (dimension > 0)
180: buffer.append(dimension);
181: switch (kind) {
182: case PRIMITIVE:
183: buffer.append(PRIMITIVE_ID);
184: break;
185: case ENUM:
186: buffer.append(ENUM_ID);
187: break;
188: case COMPONENT:
189: buffer.append(COMPONENT_ID);
190: break;
191: }
192: return buffer.append(string).toString();
193: }
194:
195: /**
196: * Returns a component type id of this type id - similar to "Class.getComponentType ()".
197: * <p>
198: * Note: This type id must be an array.
199: * @return the component type id.
200: */
201: public TypeID getComponentType() {
202: assert dimension > 0;
203: return new TypeID(kind, string, dimension - 1);
204: }
205:
206: /**
207: * Returns an array type id of this type id - opposite to "TypeID.getComponentType" method.
208: * @return the array type id
209: */
210: public TypeID getArrayType() {
211: return new TypeID(kind, string, dimension + 1);
212: }
213:
214: /**
215: * Returns whether the encoded string representation of this type id equals to the one from the specified typeid.
216: * @param o the compared type id
217: * @return true if equals
218: */
219: @Override
220: public boolean equals(Object o) {
221: return o != null && getClass() == o.getClass()
222: && encoded.equals(((TypeID) o).encoded);
223: }
224:
225: /**
226: * Returns a hash code of the type id.
227: * @return the hash code
228: */
229: @Override
230: public int hashCode() {
231: return encoded.hashCode();
232: }
233:
234: /**
235: * Returns encoded string representation of this type id.
236: * @return the string
237: */
238: @Override
239: public String toString() {
240: return encoded;
241: }
242:
243: /**
244: * Creates a new instance from an encoded string representation of type id.
245: * @param string the encoded string
246: */
247: public static TypeID createFrom(String string) {
248: return string != null ? new TypeID(string) : null;
249: }
250:
251: }
|