001/* Copyright 2011-2012 the original author or authors: 002 * 003 * Marc Palmer (marc@grailsrocks.com) 004 * Stéphane Maldini (smaldini@vmware.com) 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.grails.plugin.platform.events; 019 020import groovy.lang.Closure; 021 022import java.io.Serializable; 023import java.lang.reflect.Method; 024 025/** 026 * @author Stephane Maldini <smaldini@vmware.com> 027 * @version 1.0 028 * @file 029 * @date 09/01/12 030 * @section DESCRIPTION 031 * <p/> 032 * format : namespace://topic:package.Class#method@hashCode 033 */ 034public class ListenerId implements Serializable { 035 private static final String CLOSURE_METHOD_NAME = "call"; 036 private static final String ID_CLASS_SEPARATOR = ":"; 037 private static final String ID_METHOD_SEPARATOR = "#"; 038 private static final String ID_HASHCODE_SEPARATOR = "@"; 039 public static final String NAMESPACE_WILDCARD = "*"; 040 public static final String ID_NAMESPACE_SEPARATOR = "://"; 041 042 /*private static final Pattern idRegex = Pattern.compile( 043 "([^" + ID_NAMESPACE_SEPARATOR + "]*)?" + 044 "("+ID_NAMESPACE_SEPARATOR +")?"+ 045 "([^" + ID_CLASS_SEPARATOR + "]*)?" + 046 "(" + ID_CLASS_SEPARATOR + "([^" + ID_METHOD_SEPARATOR + "]*))?" 047 + "(" + ID_METHOD_SEPARATOR + "([^" + ID_HASHCODE_SEPARATOR + "]*))?" 048 + "(" + ID_HASHCODE_SEPARATOR + "(-?\\d*))?"); 049*/ 050 private String className; 051 private String methodName; 052 private String hashCode; 053 private String topic; 054 055 private String namespace; 056 057 public ListenerId(String namespace, String topic) { 058 this(namespace, topic, null, null, null); 059 } 060 061 public ListenerId(String namespace, String topic, String className, String methodName, String hashCode) { 062 this.className = className; 063 this.methodName = methodName; 064 this.hashCode = hashCode; 065 this.namespace = namespace; 066 if (topic != null && !topic.isEmpty()) { 067 this.topic = topic; 068 } 069 } 070 071 public String getTopic() { 072 return topic; 073 } 074 075 public void setTopic(String topic) { 076 this.topic = topic; 077 } 078 079 public String getNamespace() { 080 return namespace; 081 } 082 083 public void setNamespace(String namespace) { 084 this.namespace = namespace; 085 } 086 087 public String getClassName() { 088 return className; 089 } 090 091 public void setClassName(String className) { 092 this.className = className; 093 } 094 095 public String getMethodName() { 096 return methodName; 097 } 098 099 public void setMethodName(String methodName) { 100 this.methodName = methodName; 101 } 102 103 public String getHashCode() { 104 return hashCode; 105 } 106 107 public void setHashCode(String hashCode) { 108 this.hashCode = hashCode; 109 } 110 111 //format : namespace://topic:package.Class#method@hashCode 112 public String toString() { 113 return toStringWithoutHash() 114 + (hashCode != null ? ID_HASHCODE_SEPARATOR + hashCode : ""); 115 } 116 117 // format : namespace://topic:package.Class#method 118 public String toStringWithoutHash() { 119 return (namespace != null ? namespace + ID_NAMESPACE_SEPARATOR : "") + (topic != null ? topic : "") + (className != null ? ID_CLASS_SEPARATOR + className : "") 120 + (methodName != null ? ID_METHOD_SEPARATOR + methodName : ""); 121 } 122 123 static public ListenerId build(String namespace, String topic, Object target, Method callback) { 124 return new ListenerId(namespace, topic, target.getClass().getName(), callback.getName(), Integer.toString(target.hashCode())); 125 } 126 127 static public ListenerId build(String namespace, String topic, Class target, Method callback) { 128 return new ListenerId(namespace, topic, target.getName(), callback.getName(), null); 129 } 130 131 static public ListenerId build(String namespace, String topic, Closure target) { 132 return new ListenerId(namespace, topic, target.getClass().getName(), CLOSURE_METHOD_NAME, Integer.toString(target.hashCode())); 133 } 134 135 static public ListenerId parse(String id) { 136 //Matcher parsed = idRegex.matcher(id); 137 if (id != null) { 138 int namespaceIndex = id.indexOf(ID_NAMESPACE_SEPARATOR); 139 String _namespace = namespaceIndex != -1 ? id.substring(0, namespaceIndex) : null; 140 id = namespaceIndex != -1 ? id.substring(namespaceIndex + 3, id.length()) : id; 141 142 int classIndex = id.indexOf(ID_CLASS_SEPARATOR); 143 String _topic = id.substring(0, classIndex != -1 ? classIndex : id.length()); 144 id = classIndex != -1 ? id.substring(classIndex + 1, id.length()) : id; 145 146 int methodIndex = id.indexOf(ID_METHOD_SEPARATOR); 147 String _class = classIndex != -1 ? id.substring(0, methodIndex != -1 ? methodIndex : id.length()) : null; 148 id = methodIndex != -1 ? id.substring(methodIndex + 1, id.length()) : id; 149 150 int hashcodeIndex = id.indexOf(ID_HASHCODE_SEPARATOR); 151 String _method = methodIndex != -1 ? id.substring(0, hashcodeIndex != -1 ? hashcodeIndex : id.length()) : null; 152 String _hashcode = hashcodeIndex != -1 ? id.substring(hashcodeIndex + 1, id.length()) : null; 153 154 return new ListenerId( 155 _namespace, 156 _topic, 157 _class, 158 _method, 159 _hashcode 160 ); 161 } 162 163 return null; 164 } 165 166 public static boolean matchesTopic(String source, String target, boolean checkTargetTopic){ 167 int topicIdx = source.indexOf(NAMESPACE_WILDCARD); 168 int targetTopicIdx = target.indexOf(NAMESPACE_WILDCARD); 169 return checkTargetTopic && targetTopicIdx != -1 && source.startsWith(target.substring(0, targetTopicIdx)) || 170 topicIdx != -1 && target.startsWith(source.substring(0, topicIdx)) || 171 source.equals(target); 172 } 173 174 public static boolean matchesNamespace(String source, String target, boolean checkTargetTopic){ 175 return source.equals(NAMESPACE_WILDCARD) || 176 checkTargetTopic && target.equals(NAMESPACE_WILDCARD) || 177 source.equalsIgnoreCase(target); 178 } 179 180 public boolean matches(ListenerId target) { 181 Boolean result = null; 182 183 if (this.namespace != null && target.getNamespace() != null) { 184 result = matchesNamespace(this.namespace, target.getNamespace(), true); 185 } 186 187 if (this.topic != null) { 188 result = result == null || result; 189 result &= matchesTopic(this.topic, target.getTopic(), true); 190 } 191 192 if (this.className != null) { 193 result = result == null || result; 194 result &= this.className.equals(target.getClassName()); 195 if (this.methodName != null) { 196 result &= this.methodName.equals(target.getMethodName()); 197 if (this.hashCode != null) { 198 result &= this.hashCode.equals(target.getHashCode()); 199 } 200 } 201 } 202 203 return result != null && result; 204 } 205 206 public boolean equals(String patternId) { 207 ListenerId listener = parse(patternId); 208 return matches(listener); 209 } 210 211 @Override 212 public boolean equals(Object o) { 213 if (this == o) return true; 214 if (o == null || getClass() != o.getClass()) return false; 215 216 ListenerId listener = (ListenerId) o; 217 218 return !(className != null ? !className.equals(listener.className) : listener.className != null) && 219 !(namespace != null ? !namespace.equals(listener.namespace) : listener.namespace != null) && 220 !(hashCode != null ? !hashCode.equals(listener.hashCode) : listener.hashCode != null) && 221 !(methodName != null ? !methodName.equals(listener.methodName) : listener.methodName != null) && 222 !(topic != null ? !topic.equals(listener.topic) : listener.topic != null); 223 224 } 225 226 @Override 227 public int hashCode() { 228 int result = className != null ? className.hashCode() : 0; 229 result = 31 * result + (methodName != null ? methodName.hashCode() : 0); 230 result = 31 * result + (hashCode != null ? hashCode.hashCode() : 0); 231 result = 31 * result + (topic != null ? topic.hashCode() : 0); 232 result = 31 * result + (namespace != null ? namespace.hashCode() : 0); 233 return result; 234 } 235}