001package org.apache.archiva.event; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.InvalidObjectException; 023import java.io.ObjectStreamException; 024import java.io.Serializable; 025import java.util.*; 026 027/** 028 * Event types define a hierarchical structure of events. Each event is bound to a certain event type. 029 * All event types have a super type, only the root event type {@link EventType#ROOT} has no super type. 030 * 031 * Event types should be stored as static fields on the events itself. 032 * 033 * @param <T> The type class parameter allows to define the types in a type safe way and represents a event class, 034 * where the type is associated to. 035 */ 036public class EventType<T extends Event> implements Serializable { 037 038 039 public static final EventType<Event> ROOT = new EventType<>(); 040 041 private final String name; 042 private final EventType<? super T> superType; 043 private WeakHashMap<EventType<? extends T>, Void> subTypes; 044 045 /** 046 * Creates a type with the given name and the root type as parent. 047 * @param name the name of the new type 048 */ 049 public EventType(String name) { 050 this.superType = ROOT; 051 this.name = name; 052 } 053 054 /** 055 * Creates a event type instance with the given super type and name. 056 * 057 * @param superType The super type or <code>null</code>, if this is the root type. 058 * @param name 059 */ 060 public EventType(EventType<? super T> superType, String name) { 061 if (superType==null) { 062 throw new NullPointerException("Super Type may not be null"); 063 } 064 this.name = name; 065 this.superType = superType; 066 superType.register(this); 067 } 068 069 /** 070 * Creates the root type 071 */ 072 private EventType() { 073 this.name="ROOT"; 074 this.superType=null; 075 } 076 077 public String name() { 078 return name; 079 } 080 081 public EventType<? super T> getSuperType() { 082 return superType; 083 } 084 085 private void register(EventType<? extends T> subType) { 086 if (subTypes == null) { 087 subTypes = new WeakHashMap<>(); 088 } 089 for (EventType<? extends T> t : subTypes.keySet()) { 090 if (((t.name == null && subType.name == null) || (t.name != null && t.name.equals(subType.name)))) { 091 throw new IllegalArgumentException("EventType \"" + subType + "\"" 092 + "with parent \"" + subType.getSuperType()+"\" already exists"); 093 } 094 } 095 subTypes.put(subType, null); 096 } 097 098 099 public static List<EventType<?>> fetchSuperTypes(EventType<?> type) { 100 List<EventType<?>> typeList = new ArrayList<>(); 101 EventType<?> cType = type; 102 while (cType!=null) { 103 typeList.add(cType); 104 cType = cType.getSuperType(); 105 } 106 return typeList; 107 } 108 109 public static boolean isInstanceOf(EventType<?> type, EventType<?> baseType) { 110 EventType<?> cType = type; 111 while(cType!=null) { 112 if (cType == baseType) { 113 return true; 114 } 115 cType = cType.getSuperType(); 116 } 117 return false; 118 } 119 120 121 private Object writeReplace() throws ObjectStreamException { 122 Deque<String> path = new LinkedList<String>(); 123 EventType<?> t = this; 124 while (t != ROOT) { 125 path.addFirst(t.name); 126 t = t.superType; 127 } 128 return new EventTypeSerialization(new ArrayList<>(path)); 129 } 130 131 static class EventTypeSerialization implements Serializable { 132 private static final long serialVersionUID = 1841649460281865547L; 133 private List<String> path; 134 135 public EventTypeSerialization(List<String> path) { 136 this.path = path; 137 } 138 139 private Object readResolve() throws ObjectStreamException { 140 EventType t = ROOT; 141 for (int i = 0; i < path.size(); ++i) { 142 String p = path.get(i); 143 if (t.subTypes != null) { 144 EventType<?> s = findSubType(t.subTypes.keySet(), p); 145 if (s == null) { 146 throw new InvalidObjectException("Cannot find event type \"" + p + "\" (of " + t + ")"); 147 } 148 t = s; 149 } else { 150 throw new InvalidObjectException("Cannot find event type \"" + p + "\" (of " + t + ")"); 151 } 152 } 153 return t; 154 } 155 156 private EventType<?> findSubType(Set<EventType> subTypes, String name) { 157 for (EventType t : subTypes) { 158 if (((t.name == null && name == null) || (t.name != null && t.name.equals(name)))) { 159 return t; 160 } 161 } 162 return null; 163 } 164 165 } 166}