Clover icon

Magnolia Imaging Module 3.4.2-SUPPORT-10161

  1. Project Clover database Tue Jul 16 2019 23:33:19 EEST
  2. Package info.magnolia.imaging

File ImagingModule.java

 

Coverage histogram

../../../img/srcFileCovDistChart8.png
56% of files have more coverage

Code metrics

16
49
8
2
236
142
22
0.45
6.12
4
2.75
9.9% of code in this file is excluded from these metrics.

Classes

Class Line # Actions
ImagingModule 70 47 10.4% 20 21
0.695652269.6%
ImagingModule.LocalFilter 209 2 0% 2 0
1.0100%
 

Contributing tests

This file is covered by 3 tests. .

Source view

1    /**
2    * This file Copyright (c) 2015-2018 Magnolia International
3    * Ltd. (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10    * This file is distributed in the hope that it will be
11    * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12    * implied warranty of MERCHANTABILITY or FITNESS FOR A
13    * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14    * Redistribution, except as permitted by whichever of the GPL
15    * or MNA you select, is prohibited.
16    *
17    * 1. For the GPL license (GPL), you can redistribute and/or
18    * modify this file under the terms of the GNU General
19    * Public License, Version 3, as published by the Free Software
20    * Foundation. You should have received a copy of the GNU
21    * General Public License, Version 3 along with this program;
22    * if not, write to the Free Software Foundation, Inc., 51
23    * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24    *
25    * 2. For the Magnolia Network Agreement (MNA), this file
26    * and the accompanying materials are made available under the
27    * terms of the MNA which accompanies this distribution, and
28    * is available at http://www.magnolia-cms.com/mna.html
29    *
30    * Any modifications to this file must keep this entire header
31    * intact.
32    *
33    */
34    package info.magnolia.imaging;
35   
36    import info.magnolia.context.SystemContext;
37    import info.magnolia.module.ModuleLifecycle;
38    import info.magnolia.module.ModuleLifecycleContext;
39    import info.magnolia.objectfactory.Components;
40    import info.magnolia.observation.WorkspaceEventListenerRegistration;
41    import info.magnolia.repository.RepositoryConstants;
42   
43    import java.util.ArrayList;
44    import java.util.Arrays;
45    import java.util.Collection;
46    import java.util.Iterator;
47    import java.util.LinkedHashMap;
48    import java.util.List;
49    import java.util.Map;
50    import java.util.TreeSet;
51   
52    import javax.imageio.ImageIO;
53    import javax.imageio.spi.IIORegistry;
54    import javax.imageio.spi.ServiceRegistry;
55    import javax.inject.Inject;
56    import javax.inject.Provider;
57    import javax.jcr.RepositoryException;
58    import javax.jcr.Session;
59    import javax.jcr.observation.Event;
60   
61    import org.apache.commons.collections4.CollectionUtils;
62    import org.apache.commons.collections4.Transformer;
63    import org.apache.commons.lang3.StringUtils;
64    import org.slf4j.Logger;
65    import org.slf4j.LoggerFactory;
66   
67    /**
68    * Keeps the configuration of the imaging module.
69    */
 
70    public class ImagingModule implements ModuleLifecycle {
71   
72    private static final Logger log = LoggerFactory.getLogger(ImagingModule.class);
73   
74    public static final String IMAGING = "imaging";
75   
76    private static final Long GENERATOR_CACHE_FLUSH_DELAY = 1000L;
77   
78    private static final Long GENERATOR_CACHE_FLUSH_MAX_DELAY = 5000L;
79   
80    static final String GENERATORS_PATH = "/modules/imaging/config/generators";
81   
82    private Provider<SystemContext> systemContextProvider;
83   
84    private WorkspaceEventListenerRegistration.Handle eventHandle;
85   
86    private Map<String, ImageGenerator> generators = new LinkedHashMap<String, ImageGenerator>();
87   
88    private boolean storeGeneratedImages = true;
89   
 
90  3 toggle @Inject
91    public ImagingModule(Provider<SystemContext> systemContextProvider) {
92  3 this.systemContextProvider = systemContextProvider;
93    }
94   
95    /**
96    * @deprecated since 3.3.1 - use {@link #ImagingModule(Provider)} instead.
97    */
 
98  0 toggle @Deprecated
99    public ImagingModule() {
100  0 this(() -> Components.getComponent(SystemContext.class));
101    }
102   
103    /**
104    * Scan for additional plugins when module starts.
105    *
106    * @see ImageIO#scanForPlugins()
107    */
 
108  3 toggle @Override
109    public void start(ModuleLifecycleContext moduleLifecycleContext) {
110  3 ImageIO.scanForPlugins();
111   
112    // Outputting supported formats was previously done by the now extinct module info.magnolia:magnolia-module-imagingtools
113  3 if (log.isDebugEnabled()) {
114  0 log.debug("This lists the formats currently available to the javax.imageio package, as installed on this system.");
115  0 log.debug("Supported input formats: {}", StringUtils.join(filter(ImageIO.getReaderFormatNames()), ", "));
116  0 log.debug("Supported input mime types: {}", StringUtils.join(filter(ImageIO.getReaderMIMETypes()), ", "));
117  0 log.debug("Supported output formats: {}", StringUtils.join(filter(ImageIO.getWriterFormatNames()), ", "));
118  0 log.debug("Supported output mime types: {}", StringUtils.join(filter(ImageIO.getWriterMIMETypes()), ", "));
119    }
120   
121  3 if (moduleLifecycleContext.getPhase() == ModuleLifecycleContext.PHASE_SYSTEM_STARTUP) {
122  1 try {
123  1 eventHandle = WorkspaceEventListenerRegistration.observe(RepositoryConstants.CONFIG, GENERATORS_PATH, events -> {
124  19 while (events.hasNext()) {
125  18 Event event = events.nextEvent();
126  18 String generatorPath = null;
127  18 try {
128  18 generatorPath = StringUtils.substringAfter(event.getPath(), GENERATORS_PATH);
129  18 int idx = StringUtils.indexOf(generatorPath, "/", 1);
130  18 if (idx > 0) {
131  9 generatorPath = StringUtils.substring(generatorPath, 0, idx);
132    }
133  18 Session session = systemContextProvider.get().getJCRSession(IMAGING);
134  18 if (!generatorPath.startsWith("jcr:") && !generatorPath.startsWith("mgnl:") && session.nodeExists(generatorPath)) {
135  1 session.removeItem(generatorPath);
136  1 session.save();
137    }
138    } catch (RepositoryException e) {
139  0 log.warn("Unable to flush imaging cache for generator [{}].", generatorPath, e);
140    }
141    }
142    }).withDelay(GENERATOR_CACHE_FLUSH_DELAY, GENERATOR_CACHE_FLUSH_MAX_DELAY).withSubNodes(true).register();
143    } catch (RepositoryException e) {
144  0 log.warn("Unable to register image cache flush listener.", e);
145    }
146    }
147    }
148   
149    /**
150    * De-registers all plugins which have the {@link Thread#getContextClassLoader() current thread's context class loader}
151    * as its class loader when the module is stopped, to avoid class/resource leak.
152    *
153    * This is taken from com.twelvemonkeys.servlet.image.IIOProviderContextListener and the details are explained here:
154    * https://github.com/haraldk/TwelveMonkeys#deploying-the-plugins-in-a-web-app .
155    */
 
156  1 toggle @Override
157    public void stop(ModuleLifecycleContext moduleLifecycleContext) {
158   
159    // De-register any locally registered IIO plugins. Relies on each web app having its own context class loader.
160  1 final IIORegistry registry = IIORegistry.getDefaultInstance();
161  1 final LocalFilter localFilter = new LocalFilter(Thread.currentThread().getContextClassLoader());
162   
163  1 Iterator<Class<?>> categories = registry.getCategories();
164   
165  6 while (categories.hasNext()) {
166  5 Class<?> category = categories.next();
167  5 Iterator<?> providers = registry.getServiceProviders(category, localFilter, false);
168   
169    // Copy the providers, as de-registering while iterating over providers will lead to ConcurrentModificationExceptions.
170  5 List<Object> providersCopy = new ArrayList<>();
171  9 while (providers.hasNext()) {
172  4 providersCopy.add(providers.next());
173    }
174   
175  5 for (Object provider : providersCopy) {
176  4 registry.deregisterServiceProvider(provider);
177  4 log.debug("Unregistered locally installed provider class: {}", provider.getClass());
178    }
179    }
180   
181  1 if (eventHandle != null && moduleLifecycleContext.getPhase() == ModuleLifecycleContext.PHASE_SYSTEM_SHUTDOWN) {
182  0 try {
183  0 eventHandle.unregister();
184    } catch (RepositoryException e) {
185  0 log.warn("Unable to unregister image cache flush listener.", e);
186    }
187    }
188    }
189   
 
190    toggle public void setGenerators(Map<String, ImageGenerator> generators) {
191    this.generators = generators;
192    }
193   
 
194    toggle public Map<String, ImageGenerator> getGenerators() {
195    return generators;
196    }
197   
 
198    toggle public boolean isStoreGeneratedImages() {
199    return storeGeneratedImages;
200    }
201   
 
202    toggle public void setStoreGeneratedImages(boolean storeGeneratedImages) {
203    this.storeGeneratedImages = storeGeneratedImages;
204    }
205   
206    /**
207    * Filters the providers based on their class loader.
208    */
 
209    static class LocalFilter implements ServiceRegistry.Filter {
210    private final ClassLoader loader;
211   
 
212  1 toggle public LocalFilter(ClassLoader loader) {
213  1 this.loader = loader;
214    }
215   
 
216  20 toggle @Override
217    public boolean filter(Object provider) {
218  20 return provider.getClass().getClassLoader() == loader;
219    }
220    }
221   
222    /**
223    * Removes duplicates and returns a collection of all entries in lowercase.
224    */
 
225  0 toggle private Collection<String> filter(String... formats) {
226  0 final TreeSet<String> set = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
227  0 set.addAll(Arrays.asList(formats));
228  0 CollectionUtils.transform(set, new Transformer() {
 
229  0 toggle @Override
230    public Object transform(Object input) {
231  0 return ((String) input).toLowerCase();
232    }
233    });
234  0 return set;
235    }
236    }