001: /* Copyright 2006 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.groups;
007:
008: import java.util.ArrayList;
009: import java.util.Enumeration;
010: import java.util.List;
011: import java.util.Map;
012: import java.util.NoSuchElementException;
013:
014: import javax.naming.InvalidNameException;
015: import javax.naming.Name;
016: import javax.naming.NameParser;
017: import javax.naming.NamingException;
018:
019: import org.jasig.portal.utils.cache.CacheFactoryLocator;
020:
021: /**
022: * A composite key and type that uniquely identify a portal entity. The composite
023: * key contains a service name, which may be compound, and a native key, which is
024: * the key that identifies the entity in the local service.
025: *
026: * @author Dan Ellentuck
027: * @version $Revision: 36531 $
028: */
029: public class CompositeEntityIdentifier extends
030: org.jasig.portal.EntityIdentifier implements IGroupConstants {
031: // static vars:
032: protected static String separator;
033: protected static String NAME_CACHE = "nameCache";
034: private static Map nameCache = CacheFactoryLocator
035: .getCacheFactory().getCache(NAME_CACHE);
036:
037: static {
038: try {
039: separator = GroupServiceConfiguration.getConfiguration()
040: .getNodeSeparator();
041: } catch (Exception ex) {
042: separator = IGroupConstants.NODE_SEPARATOR;
043: }
044: }
045:
046: // instance vars:
047: protected Name compositeKey;
048: protected String cachedCompositeKey;
049: protected String cachedLocalKey;
050: protected Name cachedServiceName;
051:
052: /**
053: * @param entityKey java.lang.String
054: * @param entityType java.lang.Class
055: */
056: public CompositeEntityIdentifier(String entityKey, Class entityType)
057: throws GroupsException {
058: super (entityKey, entityType);
059: try {
060: compositeKey = parseCompoundKey(entityKey);
061: } catch (NamingException ne) {
062: throw new GroupsException("Error in group key", ne);
063: }
064: }
065:
066: /**
067: * @return javax.naming.Name
068: */
069: protected Name getCompositeKey() {
070: return compositeKey;
071: }
072:
073: /**
074: * @return java.lang.String
075: */
076: public synchronized String getKey() {
077: if (cachedCompositeKey == null) {
078: cachedCompositeKey = getCompositeKey().toString();
079: }
080: return cachedCompositeKey;
081: }
082:
083: /**
084: * @return java.lang.String
085: */
086: public synchronized String getLocalKey() {
087: if (cachedLocalKey == null) {
088: cachedLocalKey = getCompositeKey().get(size() - 1);
089: }
090: return cachedLocalKey;
091: }
092:
093: /**
094: * @return javax.naming.NameParser
095: */
096: protected NameParser getParser() {
097: return new NameParser() {
098: public Name parse(String s) throws InvalidNameException {
099: int start = 0;
100: int separatorLength = separator.length();
101: int end = s.indexOf(separator, start);
102: List list = new ArrayList(4);
103: while (end != -1) {
104: list.add(s.substring(start, end));
105: start = end + separatorLength;
106: end = s.indexOf(separator, start);
107: }
108: list.add(s.substring(start));
109: return new CompositeEntityIdentifier.NameImpl(list);
110: }
111: };
112: }
113:
114: /**
115: * If the composite key is either empty or has a single node, there is
116: * no service name.
117: * @return javax.naming.Name
118: */
119: public synchronized Name getServiceName() {
120: if (size() < 2) {
121: return null;
122: }
123: if (cachedServiceName == null) {
124: cachedServiceName = getCompositeKey().getPrefix(size() - 1);
125: }
126: return cachedServiceName;
127: }
128:
129: /**
130: * Returns a new empty Name
131: */
132: public Name newName() throws InvalidNameException {
133: return new NameImpl();
134: }
135:
136: /**
137: * @return String - the removed component
138: */
139: public String popNode() throws InvalidNameException {
140: return (String) getCompositeKey().remove(0);
141: }
142:
143: /**
144: * @return javax.naming.Name
145: */
146: public Name pushNode(String newNode) throws InvalidNameException {
147: return getCompositeKey().add(0, newNode);
148: }
149:
150: /**
151: * @param newCompositeKey javax.naming.Name
152: */
153: public synchronized void setCompositeKey(Name newCompositeKey) {
154: compositeKey = newCompositeKey;
155: cachedCompositeKey = null;
156: cachedLocalKey = null;
157: cachedServiceName = null;
158:
159: }
160:
161: /**
162: * @param newServiceName javax.naming.Name
163: */
164: public void setServiceName(Name newServiceName)
165: throws InvalidNameException {
166: Name newKey = newName().addAll(newServiceName).add(
167: getLocalKey());
168: setCompositeKey(newKey);
169: cachedServiceName = newServiceName;
170: }
171:
172: /**
173: * @return int
174: */
175: protected int size() {
176: return getCompositeKey().size();
177: }
178:
179: /**
180: * Returns a String that represents the value of this object.
181: * @return java.lang.String
182: */
183: public String toString() {
184: return "CompositeEntityIdentifier (" + type + "(" + getKey()
185: + "))";
186: }
187:
188: /**
189: * Returns a CompoundName parsed from key
190: */
191: public Name parseCompoundKey(String key) throws NamingException {
192: Name n = (Name) nameCache.get(key);
193: if (n == null) {
194: n = getParser().parse(key);
195: nameCache.put(key, n);
196: }
197: return n;
198: }
199:
200: private class NameImpl implements Name {
201: List components;
202:
203: public NameImpl() {
204: this (new ArrayList(4));
205: }
206:
207: public NameImpl(List comps) {
208: super ();
209: components = comps;
210: }
211:
212: public Name add(String comp) {
213: components.add(comp);
214: return this ;
215: }
216:
217: public Name add(int posn, String comp) {
218: components.add(posn, comp);
219: return this ;
220: }
221:
222: public Name addAll(int posn, Name n) {
223: int i = posn;
224: for (Enumeration e = n.getAll(); e.hasMoreElements(); i++) {
225: add(i, (String) e.nextElement());
226: }
227: return this ;
228: }
229:
230: public Name addAll(Name n) {
231: for (Enumeration e = n.getAll(); e.hasMoreElements();) {
232: add((String) e.nextElement());
233: }
234: return this ;
235: }
236:
237: public Object clone() {
238: List comps = (List) ((ArrayList) components).clone();
239: return new NameImpl(comps);
240: }
241:
242: public int compareTo(Object obj) {
243: if (this == obj) {
244: return 0;
245: }
246: if (!(obj instanceof Name)) {
247: throw new ClassCastException("Not a Name");
248: }
249:
250: Name name = (Name) obj;
251: int len1 = size();
252: int len2 = name.size();
253: int n = Math.min(len1, len2);
254:
255: int index1 = 0, index2 = 0;
256:
257: while (n-- != 0) {
258: String comp1 = get(index1++);
259: String comp2 = name.get(index2++);
260:
261: comp1 = comp1.trim();
262: comp2 = comp2.trim();
263:
264: int local = comp1.compareTo(comp2);
265: if (local != 0) {
266: return local;
267: }
268: }
269: return len1 - len2;
270: }
271:
272: public boolean endsWith(Name n) {
273: int startIndex = size() - n.size();
274: if (startIndex < 0 || startIndex > size()) {
275: return false;
276: }
277: Enumeration suffix = n.getAll();
278: try {
279: Enumeration mycomps = getAll();
280: while (mycomps.hasMoreElements()) {
281: String my = (String) mycomps.nextElement();
282: String his = (String) suffix.nextElement();
283: my = my.trim();
284: his = his.trim();
285: if (!(my.equals(his))) {
286: return false;
287: }
288: }
289: } catch (NoSuchElementException e) {
290: return false;
291: }
292: return true;
293: }
294:
295: public String get(int posn) {
296: return (String) components.get(posn);
297: }
298:
299: public Enumeration getAll() {
300: return new NameImplEnumerator(components, 0, components
301: .size());
302: }
303:
304: public Name getPrefix(int posn) {
305: if (posn < 0 || posn >= size()) {
306: throw new ArrayIndexOutOfBoundsException(posn);
307: }
308: return getNameComponents(0, posn);
309: }
310:
311: public Name getSuffix(int posn) {
312: if (posn < 0 || posn > size()) {
313: throw new ArrayIndexOutOfBoundsException(posn);
314: }
315: return getNameComponents(posn, size());
316: }
317:
318: public boolean isEmpty() {
319: return (components.isEmpty());
320: }
321:
322: public Object remove(int posn) throws InvalidNameException {
323: if (posn < 0 || posn >= size()) {
324: throw new InvalidNameException("Invalid position.");
325: }
326: return components.remove(posn);
327: }
328:
329: public int size() {
330: return (components.size());
331: }
332:
333: public boolean startsWith(Name n) {
334: Name myPrefix = getPrefix(n.size());
335: return (myPrefix.compareTo(n) == 0);
336: }
337:
338: public String toString() {
339: if (size() == 0) {
340: return "";
341: }
342: if (size() == 1) {
343: return get(0);
344: }
345:
346: // TODO: for jdk 1.5:
347: // StringBuilder sb = new StringBuilder();
348: StringBuffer sb = new StringBuffer();
349: for (int i = 0; i < size(); i++) {
350: if (i != 0) {
351: sb.append(separator);
352: }
353: sb.append(get(i));
354: }
355: return (sb.toString());
356: }
357:
358: public boolean equals(Object obj) {
359: if (obj == null) {
360: return false;
361: }
362: if (obj == this ) {
363: return true;
364: }
365: if (!(obj instanceof Name)) {
366: return false;
367: }
368: Name target = (Name) obj;
369: if (target.size() != this .size()) {
370: return false;
371: }
372:
373: // For our purposes this is sufficient, if not entirely correct:
374: return target.toString().equals(this .toString());
375: }
376:
377: public int hashCode() {
378: int hash = 0;
379: for (Enumeration e = getAll(); e.hasMoreElements();) {
380: String comp = (String) e.nextElement();
381: hash += comp.hashCode();
382: }
383: return hash;
384: }
385:
386: private Enumeration getComponents(int start, int limit) {
387: return new NameImplEnumerator(components, start, limit);
388: }
389:
390: private Name getNameComponents(int start, int limit) {
391: List comps = new ArrayList(limit - start);
392: for (Enumeration e = getComponents(start, limit); e
393: .hasMoreElements();) {
394: comps.add(e.nextElement());
395: }
396: return new NameImpl(comps);
397: }
398:
399: }
400:
401: private class NameImplEnumerator implements Enumeration {
402: List list;
403: int count;
404: int limit;
405:
406: NameImplEnumerator(List l, int start, int lim) {
407: list = l;
408: count = start;
409: limit = lim;
410: }
411:
412: public boolean hasMoreElements() {
413: return count < limit;
414: }
415:
416: public Object nextElement() {
417: if (count < limit) {
418: return list.get(count++);
419: }
420: throw new NoSuchElementException("NameImplEnumerator");
421: }
422: }
423:
424: }
|