1 package org.jmage.filterchain;
2
3 import org.apache.log4j.Logger;
4 import org.apache.log4j.Priority;
5 import org.jmage.ApplicationContext;
6 import org.jmage.ImageRequest;
7 import org.jmage.JmageException;
8 import org.jmage.RequestHandler;
9 import org.jmage.filter.FilterException;
10
11 import javax.media.jai.PlanarImage;
12 import java.net.URI;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Properties;
16
17 /***
18 * FilterChainManager controls all FilterChains and acts as a delegate to all it's attached
19 * FilterChainFactories. Create FilterChains by specifying a URI filterchain:com.package.FilterChain
20 * and let the delegates work out how to create it. FilterChains can be constructed out of
21 * single filters, in which case the class name of that Filter should be provided.<p>
22 * <p/>
23 * A more sophisticated way to create chains is to serialize them into XML format. See
24 * resources/xml for examples.
25 */
26 public class FilterChainManager implements RequestHandler {
27 protected List filterChainFactories;
28 protected ApplicationContext applicationContext = null;
29
30 protected static Logger log = Logger.getLogger(FilterChainManager.class.getName());
31 private static final String CHAIN = "chain";
32 private static final String SCHEME_ERROR = "unable to create FilterChain, need to specify a uri, chain:package.FilterChain";
33 private static final String FACTORIES_EMPTY_ERROR = "error, no FilterChainFactories configured";
34 private static final String FACTORY_FAILED_WARNING = "unable to create filter chain with factory, skipping: ";
35 private static final String FILTERCHAIN_ERROR = "unable to create filter chain, all factories failed to handle: ";
36 private static final String FILTERCHAIN_SUCCESS = " created FilterChain for: ";
37
38 /***
39 * Default Constructor
40 */
41 protected FilterChainManager() {
42
43 }
44
45 /***
46 * Configure FilterChainManager
47 *
48 * @param context
49 */
50 public void configure(ApplicationContext context) {
51 applicationContext = context;
52 }
53
54 /***
55 * Creates a EncoderManager for an array of given FilterChainFactories
56 *
57 * @param filterChainFactories
58 */
59 public FilterChainManager(List filterChainFactories) {
60 this.filterChainFactories = filterChainFactories;
61 }
62
63 /***
64 * Filters an ImageRequest with an existing Filterchain
65 *
66 * @param request the request
67 * @throws FilterChainException
68 * @throws FilterException
69 */
70 public void handle(ImageRequest request) throws JmageException {
71 request.setImage(this.filter(request));
72 }
73
74 /***
75 * Creates a FilterChain object to use for a given unique chainUri, denoted by a URI
76 * following the convention filterchain:com.package.FilterChain
77 *
78 * @param request the ImageRequest
79 * @return the FilterChain object.
80 * @throws FilterChainException if the filterchain cannot be constructed or handled properly
81 */
82 protected FilterChain[] create(ImageRequest request) throws FilterChainException, FilterException {
83 FilterChain[] chains = null;
84
85
86 assert (filterChainFactories.size() > 0) : FACTORIES_EMPTY_ERROR;
87
88
89 int chainSize = request.getFilterChainURI().length;
90 chains = new FilterChain[chainSize];
91
92
93 for (int i = 0; i < chainSize; i++) {
94 Iterator it = filterChainFactories.iterator();
95
96 if (!CHAIN.equals(request.getFilterChainURI()[i].getScheme())) {
97 throw new FilterChainException(SCHEME_ERROR);
98 }
99 String filterChain = request.getFilterChainURI()[i].getSchemeSpecificPart();
100 do {
101 FilterChainFactory factory = (FilterChainFactory) it.next();
102 try {
103
104 chains[i] = factory.createFrom(URI.create(this.lookupFilterChainName(filterChain)));
105 chains[i].updateConfigurableFilters(request.getFilterChainProperties() != null ? request.getFilterChainProperties() : new Properties());
106 chains[i].updateConfigurableFilters(
107 request.getFilterChainProperties().get(filterChain) != null ? (Properties) request.getFilterChainProperties().get(filterChain) : new Properties());
108 } catch (FilterChainException e) {
109 if (log.isDebugEnabled()) log.debug(FACTORY_FAILED_WARNING + factory.getClass().getName());
110 }
111 } while (chains[i] == null && it.hasNext());
112 }
113
114 if (chains[0] != null) {
115 if (log.isInfoEnabled()) log.info(FILTERCHAIN_SUCCESS + request.getFilterChainURI().toString());
116 } else {
117 if (log.isEnabledFor(Priority.ERROR)) log.error(FILTERCHAIN_ERROR + request.getFilterChainURI().toString());
118 throw new FilterChainException(FILTERCHAIN_ERROR + request.getFilterChainURI().toString());
119 }
120 return chains;
121 }
122
123 /***
124 * Filters an image through an existing FilterChain[].
125 *
126 * @param chains the FilterChain[]
127 * @param image the image
128 * @return the filtered image
129 * @throws FilterException
130 */
131 protected PlanarImage doFilter(FilterChain[] chains, PlanarImage image) throws FilterException {
132
133 for (int i = 0; i < chains.length; i++) {
134 image = chains[i].filter(image);
135 }
136 return image;
137 }
138
139 /***
140 * Convenience method combining filter creation and image filtering. Use this if you need the FilterChain
141 * only for one ImageRequest. Builds an unconfigured FilterChain and filters an image through it instantly.
142 *
143 * @param imageRequest the request
144 * @return the filtered image
145 * @throws FilterChainException if the filterchain can't be created or found
146 * @throws FilterException if the filterchain can't filter the image.
147 */
148 protected PlanarImage filter(ImageRequest imageRequest) throws FilterChainException, FilterException {
149 FilterChain[] chains = this.create(imageRequest);
150 return this.doFilter(chains, imageRequest.getImage());
151 }
152
153 protected String lookupFilterChainName(String filterChain) {
154 String filterChainName = applicationContext.getProperty(filterChain);
155 return filterChainName != null ? filterChainName : filterChain;
156 }
157
158 public String toString() {
159 return "[" + this.getClass().getName() + "#" + this.hashCode() + "]";
160 }
161 }