View Javadoc
1   /*
2    * Copyright (C) 2012-2024 RRiBbit.org
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.rribbit.retrieval;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.List;
21  import java.util.concurrent.CopyOnWriteArrayList;
22  import java.util.stream.Collectors;
23  
24  import org.rribbit.ListenerObject;
25  import org.rribbit.creation.ListenerObjectCreator;
26  import org.slf4j.Logger;
27  import org.slf4j.LoggerFactory;
28  
29  /**
30   * This {@link ListenerObjectRetriever} provides common functionality that is required by typical implementations of {@link ListenerObjectRetriever}.
31   * This includes methods for checking whether a {@link ListenerObject} matches a certain request.
32   * <p />
33   * This class uses a {@link List} of {@link ListenerObjectCreator}s for getting all {@link ListenerObject}s to search in. It does not keep a local copy of this collection, so implementations of
34   * {@link ListenerObjectCreator} are responsible of caching it.
35   * <p />
36   * This implementation is quite naieve, checking each {@link ListenerObject} in the {@link Collection} for a match everytime a request is made. Subclasses may replace this behaviour with
37   * more intelligent behaviour, such as caching of search results, or may implement {@link ListenerObjectRetriever} directly.
38   *
39   * @author G.J. Schouten
40   *
41   */
42  public class DefaultListenerObjectRetriever implements ListenerObjectRetriever {
43  
44  	private static final Logger log = LoggerFactory.getLogger(DefaultListenerObjectRetriever.class);
45  
46  	protected List<ListenerObjectCreator> listenerObjectCreators;
47  
48  	/**
49  	 * Whenever you use this constructor, be sure to set the {@link ListenerObjectCreator} with the setter provided by this class.
50  	 * If you don't, runtime {@link NullPointerException}s will occur.
51  	 */
52  	public DefaultListenerObjectRetriever() {
53  		listenerObjectCreators = new CopyOnWriteArrayList<>();
54  	}
55  
56  	/**
57  	 * This constructor is recommended, since it forces you to specify the {@link ListenerObjectCreator}. Passing a null value for this
58  	 * will result in a runtime {@link NullPointerException} whenever the {@link DefaultListenerObjectRetriever} is used.
59  	 *
60  	 * @param listenerObjectCreators
61  	 */
62  	public DefaultListenerObjectRetriever(ListenerObjectCreator... listenerObjectCreators) {
63  		this();
64  		for(ListenerObjectCreator listenerObjectCreator : listenerObjectCreators) {
65  			this.addListenerObjectCreator(listenerObjectCreator);
66  		}
67  	}
68  
69  	@Override
70  	public Collection<ListenerObject> getListenerObjects() {
71  
72  		return this.getListenerObjectsFromAllCreators();
73  	}
74  
75  	@Override
76  	public Collection<ListenerObject> getListenerObjects(Class<?> returnType) {
77  
78  		return this.getListenerObjectsFromAllCreators()
79  			.stream()
80  			.filter(listenerObject -> this.matchesReturnType(listenerObject, returnType))
81  			.collect(Collectors.toList());
82  	}
83  
84  	@Override
85  	public Collection<ListenerObject> getListenerObjects(String hint) {
86  
87  		return this.getListenerObjectsFromAllCreators()
88  			.stream()
89  			.filter(listenerObject -> this.matchesHint(listenerObject, hint))
90  			.collect(Collectors.toList());
91  	}
92  
93  	@Override
94  	public Collection<ListenerObject> getListenerObjects(Class<?> returnType, String hint) {
95  
96  		return this.getListenerObjectsFromAllCreators()
97  			.stream()
98  			.filter(listenerObject -> this.matchesHint(listenerObject, hint) && this.matchesReturnType(listenerObject, returnType))
99  			.collect(Collectors.toList());
100 	}
101 
102 	protected Collection<ListenerObject> getListenerObjectsFromAllCreators() {
103 
104 		log.debug("Getting all ListenerObjects from all ListenerObjectCreators");
105 		Collection<ListenerObject> listenerObjects = new ArrayList<>();
106 		for(ListenerObjectCreator listenerObjectCreator : listenerObjectCreators) {
107 			listenerObjects.addAll(listenerObjectCreator.getListenerObjects());
108 		}
109 		return listenerObjects;
110 	}
111 
112 	/**
113 	 * Checks whether the {@link ListenerObject} matches the hint.
114 	 *
115 	 * @param listenerObject
116 	 * @param hint
117 	 * @return whether the {@link ListenerObject} matches the hint.
118 	 */
119 	protected boolean matchesHint(ListenerObject listenerObject, String hint) {
120 
121 		if(hint == null) {
122 			throw new IllegalArgumentException("hint cannot be null!");
123 		}
124 		return listenerObject.getHints().contains(hint);
125 	}
126 
127 	/**
128 	 * Checks whether the {@link ListenerObject} matches the returntype.
129 	 *
130 	 * @param listenerObject
131 	 * @param returnType
132 	 * @return whether the {@link ListenerObject} matches the returntype.
133 	 */
134 	protected boolean matchesReturnType(ListenerObject listenerObject, Class<?> returnType) {
135 
136 		if(returnType == null) {
137 			throw new IllegalArgumentException("returnType cannot be null!");
138 		}
139 		return returnType.isAssignableFrom(listenerObject.getReturnType());
140 	}
141 
142 	/**
143 	 * Returns all {@link ListenerObjectCreator}s that are used by this {@link DefaultListenerObjectRetriever}.
144 	 *
145 	 * @return  All {@link ListenerObjectCreator}s that are used by this {@link DefaultListenerObjectRetriever}
146 	 */
147 	public List<ListenerObjectCreator> getListenerObjectCreators() {
148 		return listenerObjectCreators;
149 	}
150 
151 	/**
152 	 * Adds a {@link ListenerObjectCreator} to this {@link DefaultListenerObjectRetriever}.
153 	 *
154 	 * @param listenerObjectCreator The {@link ListenerObjectCreator} that needs to be added to this {@link DefaultListenerObjectRetriever}
155 	 */
156 	public void addListenerObjectCreator(ListenerObjectCreator listenerObjectCreator) {
157 		listenerObjectCreators.add(listenerObjectCreator);
158 	}
159 
160 	/**
161 	 * Removes all {@link ListenerObjectCreator}s from this {@link DefaultListenerObjectRetriever} and adds only the given one. After invoking this method, only the given
162 	 * {@link ListenerObjectCreator} will be used by this {@link DefaultListenerObjectRetriever}.
163 	 *
164 	 * @param listenerObjectCreator The {@link ListenerObjectCreator} that must be the sole {@link ListenerObjectCreator} used by this {@link DefaultListenerObjectRetriever}
165 	 */
166 	public void setListenerObjectCreator(ListenerObjectCreator listenerObjectCreator) {
167 		listenerObjectCreators.clear();
168 		listenerObjectCreators.add(listenerObjectCreator);
169 	}
170 }