001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004
005 This file is part of Granite Data Services.
006
007 Granite Data Services is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Library General Public License as published by
009 the Free Software Foundation; either version 2 of the License, or (at your
010 option) any later version.
011
012 Granite Data Services is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 for more details.
016
017 You should have received a copy of the GNU Library General Public License
018 along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020
021 package org.granite.gravity.adapters;
022
023 /**
024 * Adapted from Greg Wilkins code (Jetty).
025 *
026 * @author William DRAI
027 */
028 public class TopicId {
029
030 public final static String WILD = "*";
031 public final static String WILDWILD = "**";
032
033 private final static String[] ROOT = {};
034
035 private final String name;
036 private final String[] segments;
037 private final int wild;
038
039 public TopicId(String name) {
040 this.name = name;
041 if (name == null || name.length() == 0 || name.charAt(0) != '/')
042 throw new IllegalArgumentException("Illegal topic name: " + name);
043
044 if ("/".equals(name))
045 segments = ROOT;
046 else {
047 if (name.charAt(name.length() - 1) == '/')
048 throw new IllegalArgumentException("Illegal topic name (should not end with '/'): " + name);
049 segments = name.substring(1).split("\\Q/\\E", -1);
050 }
051
052 if (segments.length > 0) {
053 if (WILD.equals(segments[segments.length-1]))
054 wild = 1;
055 else if (WILDWILD.equals(segments[segments.length-1]))
056 wild = 2;
057 else
058 wild = 0;
059 }
060 else
061 wild = 0;
062 }
063
064 public boolean isWild() {
065 return wild > 0;
066 }
067
068 @Override
069 public boolean equals(Object obj) {
070 if (this == obj)
071 return true;
072
073 if (obj instanceof TopicId) {
074 TopicId other = (TopicId)obj;
075 if (isWild()) {
076 if (other.isWild())
077 return this.name.equals(other.name);
078 return matches(other);
079 }
080 if (other.isWild())
081 return other.matches(this);
082 return name.equals(other.name);
083 }
084 else if (obj instanceof String) {
085 if (isWild())
086 return matches((String)obj);
087 return name.equals(obj);
088 }
089
090 return false;
091 }
092
093 public boolean matches(TopicId name) {
094 if (name.isWild())
095 return equals(name);
096
097 switch (wild) {
098 case 0:
099 return equals(name);
100 case 1:
101 if (name.segments.length != segments.length)
102 return false;
103 for (int i = segments.length-1; i-- > 0; )
104 if (!segments[i].equals(name.segments[i]))
105 return false;
106 return true;
107
108 case 2:
109 if (name.segments.length < segments.length)
110 return false;
111 for (int i = segments.length-1; i-- > 0; )
112 if (!segments[i].equals(name.segments[i]))
113 return false;
114 return true;
115 }
116 return false;
117 }
118
119 public boolean matches(String name) {
120 if (wild == 0)
121 return this.name.equals(name);
122
123 // TODO more efficient?
124 return matches(new TopicId(name));
125 }
126
127 @Override
128 public int hashCode() {
129 return name.hashCode();
130 }
131
132 @Override
133 public String toString() {
134 return name;
135 }
136
137 public int depth() {
138 return segments.length;
139 }
140
141 public boolean isParentOf(TopicId id) {
142 if (isWild() || depth() >= id.depth())
143 return false;
144
145 for (int i = segments.length-1; i-- >0; )
146 if (!segments[i].equals(id.segments[i]))
147 return false;
148
149 return true;
150 }
151
152 public String getSegment(int i) {
153 if (i > segments.length)
154 return null;
155 return segments[i];
156 }
157
158 public static String normalize(String topicId) {
159 if (topicId == null)
160 return "/";
161 if (topicId.indexOf('.') >= 0)
162 topicId = topicId.replace('.', '/');
163 return (topicId.startsWith("/") ? topicId : ("/" + topicId));
164 }
165 }