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 Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036: package com.sun.tools.xjc.model;
037:
038: /**
039: * represents a possible number of occurence.
040: *
041: * Usually, denoted by a pair of integers like (1,1) or (5,10).
042: * A special value "unbounded" is allowed as the upper bound.
043: *
044: * <p>
045: * For example, (0,unbounded) corresponds to the '*' occurence of DTD.
046: * (0,1) corresponds to the '?' occurence of DTD.
047: *
048: * @author
049: * <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a>
050: */
051: public final class Multiplicity {
052: public final int min;
053: public final Integer max; // null is used to represent "unbounded".
054:
055: public static Multiplicity create(int min, Integer max) {
056: if (min == 0 && max == null)
057: return STAR;
058: if (min == 1 && max == null)
059: return PLUS;
060: if (max != null) {
061: if (min == 0 && max == 0)
062: return ZERO;
063: if (min == 0 && max == 1)
064: return OPTIONAL;
065: if (min == 1 && max == 1)
066: return ONE;
067: }
068: return new Multiplicity(min, max);
069: }
070:
071: private Multiplicity(int min, Integer max) {
072: this .min = min;
073: this .max = max;
074: }
075:
076: public boolean equals(Object o) {
077: if (!(o instanceof Multiplicity))
078: return false;
079:
080: Multiplicity that = (Multiplicity) o;
081:
082: if (this .min != that.min)
083: return false;
084: if (this .max != null ? !this .max.equals(that.max)
085: : that.max != null)
086: return false;
087:
088: return true;
089: }
090:
091: public int hashCode() {
092: int result;
093: result = min;
094: result = 29 * result + (max != null ? max.hashCode() : 0);
095: return result;
096: }
097:
098: /** returns true if the multiplicity is (1,1). */
099: public boolean isUnique() {
100: if (max == null)
101: return false;
102: return min == 1 && max == 1;
103: }
104:
105: /** returns true if the multiplicity is (0,1) */
106: public boolean isOptional() {
107: if (max == null)
108: return false;
109: return min == 0 && max == 1;
110: }
111:
112: /** returns true if the multiplicity is (0,1) or (1,1). */
113: public boolean isAtMostOnce() {
114: if (max == null)
115: return false;
116: return max <= 1;
117: }
118:
119: /** returns true if the multiplicity is (0,0). */
120: public boolean isZero() {
121: if (max == null)
122: return false;
123: return max == 0;
124: }
125:
126: /**
127: * Returns true if the multiplicity represented by this object
128: * completely includes the multiplicity represented by the
129: * other object. For example, we say [1,3] includes [1,2] but
130: * [2,4] doesn't include [1,3].
131: */
132: public boolean includes(Multiplicity rhs) {
133: if (rhs.min < min)
134: return false;
135: if (max == null)
136: return true;
137: if (rhs.max == null)
138: return false;
139: return rhs.max <= max;
140: }
141:
142: /**
143: * Returns the string representation of the 'max' property.
144: * Either a number or a token "unbounded".
145: */
146: public String getMaxString() {
147: if (max == null)
148: return "unbounded";
149: else
150: return max.toString();
151: }
152:
153: /** gets the string representation.
154: * mainly debug purpose.
155: */
156: public String toString() {
157: return "(" + min + ',' + getMaxString() + ')';
158: }
159:
160: /** the constant representing the (0,0) multiplicity. */
161: public static final Multiplicity ZERO = new Multiplicity(0, 0);
162:
163: /** the constant representing the (1,1) multiplicity. */
164: public static final Multiplicity ONE = new Multiplicity(1, 1);
165:
166: /** the constant representing the (0,1) multiplicity. */
167: public static final Multiplicity OPTIONAL = new Multiplicity(0, 1);
168:
169: /** the constant representing the (0,unbounded) multiplicity. */
170: public static final Multiplicity STAR = new Multiplicity(0, null);
171:
172: /** the constant representing the (1,unbounded) multiplicity. */
173: public static final Multiplicity PLUS = new Multiplicity(1, null);
174:
175: // arithmetic methods
176: //============================
177: public static Multiplicity choice(Multiplicity lhs, Multiplicity rhs) {
178: return create(Math.min(lhs.min, rhs.min),
179: (lhs.max == null || rhs.max == null) ? null
180: : (Integer) Math.max(lhs.max, rhs.max));
181: }
182:
183: public static Multiplicity group(Multiplicity lhs, Multiplicity rhs) {
184: return create(lhs.min + rhs.min,
185: (lhs.max == null || rhs.max == null) ? null
186: : (Integer) (lhs.max + rhs.max));
187: }
188:
189: public static Multiplicity multiply(Multiplicity lhs,
190: Multiplicity rhs) {
191: int min = lhs.min * rhs.min;
192: Integer max;
193: if (isZero(lhs.max) || isZero(rhs.max))
194: max = 0;
195: else if (lhs.max == null || rhs.max == null)
196: max = null;
197: else
198: max = lhs.max * rhs.max;
199: return create(min, max);
200: }
201:
202: private static boolean isZero(Integer i) {
203: return i != null && i == 0;
204: }
205:
206: public static Multiplicity oneOrMore(Multiplicity c) {
207: if (c.max == null)
208: return c; // (x,*) => (x,*)
209: if (c.max == 0)
210: return c; // (0,0) => (0,0)
211: else
212: return create(c.min, null); // (x,y) => (x,*)
213: }
214:
215: public Multiplicity makeOptional() {
216: if (min == 0)
217: return this ;
218: return create(0, max);
219: }
220:
221: public Multiplicity makeRepeated() {
222: if (max == null || max == 0)
223: return this ; // (0,0)* = (0,0) and (n,unbounded)* = (n,unbounded)
224: return create(min, null);
225: }
226: }
|