1 package org.apache.torque.generator.qname;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.commons.lang.StringUtils;
23
24
25 /**
26 * This class contains a name which has a namespace. The namespace defines the
27 * scope where the name is valid, and is made up of hierarchical bits
28 * separated by a dot (<code>SEPARATOR<code>).
29 * A qualified name is in the scope of its own namespace and all children
30 * namespaces of its own namespace (i.e. the namespaces "deeper down"
31 * the hierarchy). For example, the namespace org.apache.torque
32 * is in the scope of org.apache but not in the scope of
33 * org.apache.torque.generator.
34 * As a special case, if the namespace is the empty String,
35 * the name is valid in all namespaces.
36 *
37 * The namespace and the name are also separated by a dot
38 * (<code>SEPARATOR<code>).
39 *
40 * Instances of this class are immutable. To prevent mutable subclasses,
41 * this class is final.
42 */
43 public final class QualifiedName
44 {
45 /**
46 * The separator between namespace parts and between namespacee
47 * and local name in the string representation of a QualifiedName.
48 */
49 public static final char SEPARATOR = '.';
50
51 /**
52 * The local name part of the qualifiedName. Is never null or empty.
53 */
54 private String name;
55
56 /**
57 * The namespace of the qualifiedName. Is never null.
58 */
59 private Namespace namespace;
60
61 /**
62 * Creates a QualifiedName from its string representation, which is
63 * namespace:name. The namespace part may be empty (in which case
64 * the default namespace is used), but not the name part.
65 *
66 * @param qualifiedName the string representation of the QualifiedName,
67 * must contain a non-empty name part.
68 * @throws NullPointerException if qualifiedName is null
69 */
70 public QualifiedName(String qualifiedName)
71 {
72 this(qualifiedName, (Namespace) null);
73 }
74
75 /**
76 * Creates a QualifiedName from a fully qualified name or the name and the
77 * namespace parts of a QualifiedName.
78 *
79 * @param nameOrQualifiedName either the name part of the QualifiedName,
80 * or a fully qualified name. May not be null and must contain
81 * an non-empty name part.
82 * @param defaultNamespace the namespace of the QualifiedName,
83 * may be null if nameOrQualifiedName has a namespace part.
84 *
85 * @throws IllegalArgumentException if name has an empty name part, or
86 * if no namespace is found (nameOrQualifiedName has no namespace
87 * part and defaultNamespace is null)
88 * @throw NullPointerException if name is null.
89 */
90 public QualifiedName(String nameOrQualifiedName, String defaultNamespace)
91 {
92 this(nameOrQualifiedName,
93 defaultNamespace != null
94 ? new Namespace(defaultNamespace)
95 : null);
96 }
97
98 /**
99 * Creates a QualifiedName from a fully qualified name or the name and the
100 * namespace parts of a QualifiedName.
101 *
102 * @param nameOrQualifiedName either the name part of the QualifiedName,
103 * or a fully qualified name. May not be null and must contain
104 * an non-empty name part.
105 * @param defaultNamespace the namespace of the QualifiedName,
106 * may be null if nameOrQualifiedName has a namespace part.
107 *
108 * @throws IllegalArgumentException if name has an empty name part, or
109 * if no namespace is found (nameOrQualifiedName has no namespace
110 * part and defaultNamespace is null)
111 * @throw NullPointerException if name is null.
112 */
113 public QualifiedName(String nameOrQualifiedName, Namespace defaultNamespace)
114 {
115 if (nameOrQualifiedName == null)
116 {
117 throw new NullPointerException(
118 "nameOrQualifiedName must not be null");
119 }
120 int dotIndex = nameOrQualifiedName.lastIndexOf(SEPARATOR);
121 if (dotIndex == -1)
122 {
123 if (defaultNamespace == null)
124 {
125 defaultNamespace = Namespace.ROOT_NAMESPACE;
126 }
127 setName(nameOrQualifiedName);
128 this.namespace = defaultNamespace;
129 }
130 else
131 {
132 setName(nameOrQualifiedName.substring(dotIndex + 1).trim());
133 String namespacePart
134 = nameOrQualifiedName.substring(0, dotIndex).trim();
135 setNamespace(namespacePart);
136 }
137 }
138
139 /**
140 * Returns the name part of the QualifiedName.
141 *
142 * @return the name part of the QualifiedName, never null.
143 */
144 public String getName()
145 {
146 return name;
147 }
148
149 /**
150 * Sets the name part of this Qualified name.
151 * This method is private because this object is immutable.
152 *
153 * @param name the name, not blank,
154 * must not contain a dot (<code>SEPARATOR</code>).
155 */
156 private void setName(String name)
157 {
158 if (name.indexOf(SEPARATOR) != -1)
159 {
160 throw new IllegalArgumentException(
161 "name \"" + name + "\" must not contain "
162 + SEPARATOR);
163 }
164 if (StringUtils.isBlank(name))
165 {
166 throw new IllegalArgumentException("name must not be blank");
167 }
168 this.name = name;
169 }
170
171 /**
172 * Sets the namespace part of this Qualified name.
173 * This method is private because this object is immutable.
174 *
175 * @param namespace the name, not null,
176 * must not contain <code>NAMESPACE_NAME_SEPARATOR</code>
177 */
178 private void setNamespace(String namespace)
179 {
180 this.namespace = new Namespace(namespace);
181 }
182
183 /**
184 * Returns the namespace of the QualifiedName.
185 *
186 * @return the namespace of the QualifiedName, may be null.
187 */
188 public Namespace getNamespace()
189 {
190 return namespace;
191 }
192
193 /**
194 * Returns if this qualified name is visible from another namespace.
195 * This is true if the namespace is a "child" of this
196 * qualified name's namespace.
197 * Note that for being a child, all the parts of the namespace separated
198 * by a dot must be equal.
199 * For example, "org.apache.torque:name" is visible from the
200 * namespaces quot;org.apache.torque.generator" and
201 * quot;org.apache.torque", but not from "org.apache".
202 *
203 * @param otherNamespace the namespace against this QualifiedName
204 * should be checked, not null.
205 *
206 * @return true if this QualifiedName is visible from the given namespace,
207 * false otherwise.
208 *
209 * @throws NullPointerException if otherNamespace is null.
210 */
211 public boolean isVisibleFrom(Namespace otherNamespace)
212 {
213 return namespace.isVisibleFrom(otherNamespace);
214 }
215
216 /**
217 * Returns the parent of the Qualified name's namespace.
218 * If this qualified name is in the root namespace, the root namespace
219 * is returned.
220 *
221 * @return the parent namespace of the qualified name's namespace,
222 * never null.
223 *
224 * @see Namespace#getParent()
225 */
226 public Namespace getParentNamespace()
227 {
228 return namespace.getParent();
229 }
230
231 /**
232 * Returns if the namespace of this qualified name is the root namespace.
233 *
234 * @return true if the namespace is the root namespace, false otherwise.
235 */
236 public boolean isInRootNamespace()
237 {
238 return namespace.isRoot();
239 }
240
241 /**
242 * Returns the String representation of the QualifiedName,
243 * which is namespace.name if namespace is not empty,
244 * or name if namespace is empty.
245 *
246 * @return a String representation of the QualifiedName.
247 */
248 @Override
249 public String toString()
250 {
251 if (isInRootNamespace())
252 {
253 return name;
254 }
255 return namespace.toString() + SEPARATOR + name;
256 }
257
258 /**
259 * Returns if this object equals another object. This is the case if
260 * the other object is also a QualifiedName and its name and namespace
261 * are the same as this object's name and namespace.
262 *
263 * @param o the other object to compare this object to.
264 * @return true if this object equals the other object, false otherwise.
265 *
266 * @see java.lang.Object#equals(Object)
267 */
268 @Override
269 public boolean equals(Object o)
270 {
271 if (!(o instanceof QualifiedName))
272 {
273 return false;
274 }
275
276 QualifiedName qualifiedName = (QualifiedName) o;
277
278 if (!qualifiedName.name.equals(name))
279 {
280 return false;
281 }
282
283 return qualifiedName.namespace.equals(namespace);
284 }
285
286 /**
287 * Returns a hashcode for the QualifiedName. The hashcode is consistent
288 * with equals.
289 *
290 * @return a hashcode for the qualified name.
291 *
292 * @see java.lang.Object#hashCode()
293 */
294 @Override
295 public int hashCode()
296 {
297 return toString().hashCode();
298 }
299 }