001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.resiliency.spi.agent.annotation;
016    
017    import java.lang.reflect.Field;
018    import java.lang.reflect.Modifier;
019    
020    import java.util.LinkedList;
021    import java.util.Map;
022    import java.util.Queue;
023    import java.util.concurrent.ConcurrentHashMap;
024    import java.util.concurrent.ConcurrentMap;
025    
026    /**
027     * @author Shuyang Zhou
028     */
029    public class DistributedRegistry {
030    
031            public static boolean isDistributed(String name, Direction direction) {
032                    Direction registeredDirection = _exactDirections.get(name);
033    
034                    if ((registeredDirection == direction) ||
035                            (registeredDirection == Direction.DUPLEX)) {
036    
037                            return true;
038                    }
039    
040                    if (registeredDirection != null) {
041                            return false;
042                    }
043    
044                    for (Map.Entry<String, Direction> entry :
045                                    _postfixDirections.entrySet()) {
046    
047                            String postfix = entry.getKey();
048    
049                            if (name.endsWith(postfix)) {
050                                    registeredDirection = entry.getValue();
051    
052                                    if ((registeredDirection == direction) ||
053                                            (registeredDirection == Direction.DUPLEX)) {
054    
055                                            return true;
056                                    }
057                            }
058                    }
059    
060                    for (Map.Entry<String, Direction> entry :
061                                    _prefixDirections.entrySet()) {
062    
063                            String prefix = entry.getKey();
064    
065                            if (name.startsWith(prefix)) {
066                                    registeredDirection = entry.getValue();
067    
068                                    if ((registeredDirection == direction) ||
069                                            (registeredDirection == Direction.DUPLEX)) {
070    
071                                            return true;
072                                    }
073                            }
074                    }
075    
076                    return false;
077            }
078    
079            public static void registerDistributed(Class<?> clazz) {
080                    processDistributed(clazz, true);
081            }
082    
083            public static void registerDistributed(
084                    String name, Direction direction, MatchType matchType) {
085    
086                    if (matchType.equals(MatchType.POSTFIX)) {
087                            _postfixDirections.put(name, direction);
088                    }
089                    else if (matchType.equals(MatchType.PREFIX)) {
090                            _prefixDirections.put(name, direction);
091                    }
092                    else {
093                            _exactDirections.put(name, direction);
094                    }
095            }
096    
097            public static void unregisterDistributed(Class<?> clazz) {
098                    processDistributed(clazz, false);
099            }
100    
101            public static boolean unregisterDistributed(
102                    String name, Direction direction, MatchType matchType) {
103    
104                    if (matchType.equals(MatchType.POSTFIX)) {
105                            if (direction == null) {
106                                    direction = _postfixDirections.remove(name);
107    
108                                    if (direction != null) {
109                                            return true;
110                                    }
111    
112                                    return false;
113                            }
114    
115                            return _postfixDirections.remove(name, direction);
116                    }
117                    else if (matchType.equals(MatchType.PREFIX)) {
118                            if (direction == null) {
119                                    direction = _prefixDirections.remove(name);
120    
121                                    if (direction != null) {
122                                            return true;
123                                    }
124    
125                                    return false;
126                            }
127    
128                            return _prefixDirections.remove(name, direction);
129                    }
130                    else {
131                            if (direction == null) {
132                                    direction = _exactDirections.remove(name);
133    
134                                    if (direction != null) {
135                                            return true;
136                                    }
137    
138                                    return false;
139                            }
140    
141                            return _exactDirections.remove(name, direction);
142                    }
143            }
144    
145            protected static void processDistributed(Class<?> clazz, boolean register) {
146                    Queue<Class<?>> queue = new LinkedList<>();
147    
148                    queue.offer(clazz);
149    
150                    Class<?> currentClass = null;
151    
152                    while ((currentClass = queue.poll()) != null) {
153                            Field[] fields = currentClass.getDeclaredFields();
154    
155                            for (Field field : fields) {
156                                    Distributed distributed = field.getAnnotation(
157                                            Distributed.class);
158    
159                                    if (distributed == null) {
160                                            continue;
161                                    }
162    
163                                    int modifiers = field.getModifiers();
164    
165                                    if (!Modifier.isPublic(modifiers) ||
166                                            !Modifier.isStatic(modifiers) ||
167                                            !Modifier.isFinal(modifiers) ||
168                                            (field.getType() != String.class)) {
169    
170                                            continue;
171                                    }
172    
173                                    try {
174                                            String name = (String)field.get(null);
175    
176                                            if (register) {
177                                                    registerDistributed(
178                                                            name, distributed.direction(),
179                                                            distributed.matchType());
180                                            }
181                                            else {
182                                                    unregisterDistributed(
183                                                            name, distributed.direction(),
184                                                            distributed.matchType());
185                                            }
186                                    }
187                                    catch (Throwable t) {
188                                            throw new RuntimeException(t);
189                                    }
190                            }
191    
192                            Class<?> supperClass = currentClass.getSuperclass();
193    
194                            if ((supperClass != null) && (supperClass != Object.class)) {
195                                    queue.offer(supperClass);
196                            }
197    
198                            Class<?>[] interfaceClasses = currentClass.getInterfaces();
199    
200                            for (Class<?> interfaceClass : interfaceClasses) {
201                                    if (!queue.contains(interfaceClass)) {
202                                            queue.offer(interfaceClass);
203                                    }
204                            }
205                    }
206            }
207    
208            private static final ConcurrentMap<String, Direction> _exactDirections =
209                    new ConcurrentHashMap<>();
210            private static final ConcurrentMap<String, Direction> _postfixDirections =
211                    new ConcurrentHashMap<>();
212            private static final ConcurrentMap<String, Direction> _prefixDirections =
213                    new ConcurrentHashMap<>();
214    
215    }