View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.common.processing;
20  
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.stream.Stream;
27  
28  import org.apache.logging.log4j.LogManager;
29  import org.apache.logging.log4j.Logger;
30  
31  /**
32   * Base implementation of a processable collection.
33   * 
34   * @author Matthias Eichner
35   */
36  public class MCRProcessableDefaultCollection implements MCRProcessableCollection {
37  
38      private static Logger LOGGER = LogManager.getLogger();
39  
40      private String name;
41  
42      private final List<MCRProcessable> processables;
43  
44      private Map<String, Object> properties;
45  
46      private final List<MCRProcessableCollectionListener> listenerList;
47  
48      /**
49       * Creates a new collection with the given a human readable name.
50       * 
51       * @param name name of this collection
52       */
53      public MCRProcessableDefaultCollection(String name) {
54          this.name = name;
55          this.processables = Collections.synchronizedList(new ArrayList<>());
56          this.properties = new HashMap<>();
57          this.listenerList = Collections.synchronizedList(new ArrayList<>());
58      }
59  
60      /**
61       * Returns the human readable name of this collection.
62       */
63      public String getName() {
64          return name;
65      }
66  
67      @Override
68      public void add(MCRProcessable processable) {
69          this.processables.add(processable);
70          fireAdded(processable);
71      }
72  
73      @Override
74      public void remove(MCRProcessable processable) {
75          this.processables.remove(processable);
76          fireRemoved(processable);
77      }
78  
79      @Override
80      public Stream<MCRProcessable> stream() {
81          List<MCRProcessable> snapshot;
82          synchronized (this.processables) {
83              snapshot = new ArrayList<>(this.processables);
84          }
85          return snapshot.stream();
86      }
87  
88      @Override
89      public boolean isEmpty() {
90          return this.processables.isEmpty();
91      }
92  
93      @Override
94      public Map<String, Object> getProperties() {
95          return this.properties;
96      }
97  
98      public void setProperty(String propertyName, Object propertyValue) {
99          Object oldValue = this.properties.get(propertyName);
100         if (oldValue == null && propertyValue == null) {
101             return;
102         }
103         if (propertyValue == null) {
104             this.properties.remove(propertyName);
105             firePropertyChanged(propertyName, oldValue, null);
106             return;
107         }
108         if (propertyValue.equals(oldValue)) {
109             return;
110         }
111         this.properties.put(propertyName, propertyValue);
112         firePropertyChanged(propertyName, oldValue, propertyValue);
113     }
114 
115     @Override
116     public void addListener(MCRProcessableCollectionListener listener) {
117         this.listenerList.add(listener);
118     }
119 
120     @Override
121     public void removeListener(MCRProcessableCollectionListener listener) {
122         this.listenerList.remove(listener);
123     }
124 
125     protected void fireAdded(MCRProcessable processable) {
126         List<MCRProcessableCollectionListener> listeners = listenersSnapshot();
127         listeners.forEach(listener -> {
128             try {
129                 listener.onAdd(this, processable);
130             } catch (Exception exc) {
131                 LOGGER.error("Unable to inform collection listener due internal error", exc);
132             }
133         });
134     }
135 
136     protected void fireRemoved(MCRProcessable processable) {
137         List<MCRProcessableCollectionListener> listeners = listenersSnapshot();
138         listeners.forEach(listener -> {
139             try {
140                 listener.onRemove(this, processable);
141             } catch (Exception exc) {
142                 LOGGER.error("Unable to inform collection listener due internal error", exc);
143             }
144         });
145     }
146 
147     protected void firePropertyChanged(String propertyName, Object oldValue, Object newValue) {
148         List<MCRProcessableCollectionListener> listeners = listenersSnapshot();
149         listeners.forEach(listener -> {
150             try {
151                 listener.onPropertyChange(this, propertyName, oldValue, newValue);
152             } catch (Exception exc) {
153                 LOGGER.error("Unable to inform collection listener due internal error", exc);
154             }
155         });
156     }
157 
158     private List<MCRProcessableCollectionListener> listenersSnapshot() {
159         synchronized (this.listenerList) {
160             return new ArrayList<>(this.listenerList);
161         }
162     }
163 
164 }