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 021package org.granite.gravity.adapters; 022 023/** 024 * Adapted from Greg Wilkins code (Jetty). 025 * 026 * @author William DRAI 027 */ 028public 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}