001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.monitoring.reporting.web.handler.internal;
018    
019    import org.apache.commons.monitoring.MonitoringException;
020    import org.apache.commons.monitoring.reporting.web.handler.api.Template;
021    import org.apache.commons.monitoring.reporting.web.handler.api.TemplateHelper;
022    import org.apache.commons.monitoring.reporting.web.template.MapBuilder;
023    
024    import javax.servlet.http.HttpServletRequest;
025    import javax.servlet.http.HttpServletResponse;
026    import java.io.IOException;
027    import java.lang.reflect.InvocationTargetException;
028    import java.lang.reflect.Method;
029    import java.util.List;
030    import java.util.concurrent.CopyOnWriteArrayList;
031    import java.util.regex.Matcher;
032    
033    public class Invoker {
034        private final Object instance;
035        private final Method method;
036        private final String name;
037        private final List<ParameterExtractor<?>> parameters = new CopyOnWriteArrayList<ParameterExtractor<?>>();
038    
039        public Invoker(final Object instance, final Method method, final String name) {
040            this.instance = instance;
041            this.method = method;
042            this.name = name;
043        }
044    
045        public void invoke(final HttpServletRequest request, final HttpServletResponse response, final Matcher matcher) {
046            final Object[] params = new Object[parameters.size()];
047            for (int i = 0; i < params.length; i++) {
048                params[i] = parameters.get(i).extract(request, response, matcher);
049            }
050            try {
051                final Object result = method.invoke(instance, params);
052                if (Template.class.isInstance(result)) {
053                    final Template template = Template.class.cast(result);
054                    final TemplateHelper helper = new TemplateHelperExtractor(name).extract(request, response, matcher);
055                    if (template.isHtml()) {
056                        helper.renderHtml(template.getTemplate(), template.getUserParams());
057                    } else {
058                        helper.renderPlain(template.getTemplate(), template.getUserParams());
059                    }
060                } else if (result != null) {
061                    response.getWriter().write(result.toString());
062                }
063            } catch (final InvocationTargetException e) {
064                throw new MonitoringException(e.getCause());
065            } catch (final Exception e) {
066                throw new MonitoringException(e);
067            }
068        }
069    
070        public void addRequestParameter() {
071            parameters.add(new RequestExtractor());
072        }
073    
074        public void addResponseParameter() {
075            parameters.add(new ResponseExtractor());
076        }
077    
078        public void addTemplateHelper(final String plugin) {
079            parameters.add(new TemplateHelperExtractor(plugin));
080        }
081    
082        public void addSegmentParameter(final Class<?> clazz, final int partIdx) {
083            if (String.class.equals(clazz)) {
084                parameters.add(new StringSegmentExtractor(partIdx));
085            } else if (Long.TYPE.equals(clazz)) {
086                parameters.add(new LongSegmentExtractor(partIdx));
087            } else if (Integer.TYPE.equals(clazz)) {
088                parameters.add(new IntSegmentExtractor(partIdx));
089            } else if (String[].class.equals(clazz)) {
090                parameters.add(new StringArraySegmentExtractor(partIdx));
091            } else {
092                throw new IllegalArgumentException(clazz.getName() + " not handled");
093            }
094        }
095    
096        protected static interface ParameterExtractor<T> {
097            T extract(HttpServletRequest request, HttpServletResponse response, Matcher matcher);
098        }
099    
100        protected static class TemplateHelperExtractor implements ParameterExtractor<TemplateHelper> {
101            private final String plugin;
102    
103            public TemplateHelperExtractor(final String plugin) {
104                this.plugin = plugin;
105            }
106    
107            @Override
108            public TemplateHelper extract(final HttpServletRequest request, final HttpServletResponse response, final Matcher matcher) {
109                try {
110                    return new TemplateHelper(response.getWriter(), new MapBuilder<String, Object>().set("templateId", plugin).build());
111                } catch (final IOException e) {
112                    throw new MonitoringException(e);
113                }
114            }
115        }
116    
117        protected static class RequestExtractor implements ParameterExtractor<HttpServletRequest> {
118            @Override
119            public HttpServletRequest extract(final HttpServletRequest request, final HttpServletResponse response, final Matcher matcher) {
120                return request;
121            }
122        }
123    
124        protected static class ResponseExtractor implements ParameterExtractor<HttpServletResponse> {
125            @Override
126            public HttpServletResponse extract(final HttpServletRequest request, final HttpServletResponse response, final Matcher matcher) {
127                return response;
128            }
129        }
130    
131        protected static class StringSegmentExtractor implements ParameterExtractor<String> {
132            private final int index;
133    
134            public StringSegmentExtractor(final int index) {
135                this.index = index;
136            }
137    
138            @Override
139            public String extract(final HttpServletRequest request, final HttpServletResponse response, final Matcher matcher) {
140                return matcher.group(index);
141            }
142        }
143    
144        protected static class StringArraySegmentExtractor implements ParameterExtractor<String[]> {
145            private final int index;
146    
147            public StringArraySegmentExtractor(final int index) {
148                this.index = index;
149            }
150    
151            @Override
152            public String[] extract(final HttpServletRequest request, final HttpServletResponse response, final Matcher matcher) {
153                return matcher.group(index).split("/");
154            }
155        }
156    
157        protected static class LongSegmentExtractor implements ParameterExtractor<Long> {
158            private final int index;
159    
160            public LongSegmentExtractor(final int index) {
161                this.index = index;
162            }
163    
164            @Override
165            public Long extract(final HttpServletRequest request, final HttpServletResponse response, final Matcher matcher) {
166                return Long.parseLong(matcher.group(index));
167            }
168        }
169    
170        protected static class IntSegmentExtractor implements ParameterExtractor<Integer> {
171            private final int index;
172    
173            public IntSegmentExtractor(final int index) {
174                this.index = index;
175            }
176    
177            @Override
178            public Integer extract(final HttpServletRequest request, final HttpServletResponse response, final Matcher matcher) {
179                return Integer.parseInt(matcher.group(index));
180            }
181        }
182    }