001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.annotation;
014
015import static org.apache.juneau.rest.RestContext.*;
016import static org.apache.juneau.rest.util.RestUtils.*;
017import static org.apache.juneau.internal.CollectionUtils.*;
018
019import java.util.logging.*;
020
021import static org.apache.juneau.internal.StringUtils.*;
022import static org.apache.juneau.html.HtmlDocSerializer.*;
023import static org.apache.juneau.internal.ArrayUtils.*;
024import static org.apache.juneau.internal.ClassUtils.*;
025import static org.apache.juneau.parser.Parser.*;
026
027import org.apache.juneau.*;
028import org.apache.juneau.httppart.*;
029import org.apache.juneau.internal.*;
030import org.apache.juneau.parser.*;
031import org.apache.juneau.reflect.*;
032import org.apache.juneau.rest.*;
033import org.apache.juneau.rest.annotation.AnnotationUtils;
034import org.apache.juneau.rest.annotation.Logging;
035import org.apache.juneau.rest.util.*;
036import org.apache.juneau.rest.widget.*;
037import org.apache.juneau.serializer.*;
038import org.apache.juneau.svl.*;
039import org.apache.juneau.utils.*;
040
041/**
042 * Applies {@link RestResource} annotations to a {@link PropertyStoreBuilder}.
043 */
044@Deprecated
045public class RestResourceConfigApply extends ConfigApply<RestResource> {
046
047   /**
048    * Constructor.
049    *
050    * @param c The annotation class.
051    * @param r The resolver for resolving values in annotations.
052    */
053   public RestResourceConfigApply(Class<RestResource> c, VarResolverSession r) {
054      super(c, r);
055   }
056
057   @Override
058   public void apply(AnnotationInfo<RestResource> ai, PropertyStoreBuilder psb) {
059      RestResource a = ai.getAnnotation();
060      String s = null;
061      ClassInfo c = ai.getClassOn();
062
063      for (Property p1 : a.properties()) {
064         psb.set(p1.name(), string(p1.value()));  // >>> DEPRECATED - Remove in 9.0 <<<
065         psb.addTo(REST_properties, string(p1.name()), string(p1.value()));
066      }
067
068      for (String p1 : a.flags()) {
069         psb.set(p1, true);  // >>> DEPRECATED - Remove in 9.0 <<<
070         psb.addTo(REST_properties, string(p1), true);
071      }
072
073      if (a.serializers().length > 0)
074         psb.set(REST_serializers, merge(ObjectUtils.toType(psb.peek(REST_serializers), Object[].class), a.serializers()));
075
076      if (a.parsers().length > 0)
077         psb.set(REST_parsers, merge(ObjectUtils.toType(psb.peek(REST_parsers), Object[].class), a.parsers()));
078
079      if (a.partSerializer() != HttpPartSerializer.Null.class)
080         psb.set(REST_partSerializer, a.partSerializer());
081
082      if (a.partParser() != HttpPartParser.Null.class)
083         psb.set(REST_partParser, a.partParser());
084
085      psb.addTo(REST_encoders, a.encoders());
086
087      if (a.produces().length > 0)
088         psb.set(REST_produces, strings(a.produces()));
089
090      if (a.consumes().length > 0)
091         psb.set(REST_consumes, strings(a.consumes()));
092
093      for (String ra : strings(a.attrs())) {
094         String[] ra2 = RestUtils.parseKeyValuePair(ra);
095         if (ra2 == null)
096            throw new FormattedRuntimeException("Invalid default request attribute specified: ''{0}''.  Must be in the format: ''Name: value''", ra);
097         if (isNotEmpty(ra2[1]))
098            psb.addTo(REST_attrs, ra2[0], ra2[1]);
099      }
100
101      for (String header : strings(a.defaultRequestHeaders())) {
102         String[] h = RestUtils.parseHeader(header);
103         if (h == null)
104            throw new FormattedRuntimeException("Invalid default request header specified: ''{0}''.  Must be in the format: ''Header-Name: header-value''", header);
105         if (isNotEmpty(h[1]))
106            psb.addTo(REST_defaultRequestHeaders, h[0], h[1]);
107      }
108
109      if (a.defaultAccept().length() > 0) {
110         s = string(a.defaultAccept());
111         if (isNotEmpty(s))
112            psb.addTo(REST_defaultRequestHeaders, "Accept", s);
113      }
114
115      if (a.defaultContentType().length() > 0) {
116         s = string(a.defaultContentType());
117         if (isNotEmpty(s))
118            psb.addTo(REST_defaultRequestHeaders, "Content-Type", s);
119
120      }
121
122      for (String header : strings(a.defaultResponseHeaders())) {
123         String[] h = parseHeader(header);
124         if (h == null)
125            throw new FormattedRuntimeException("Invalid default response header specified: ''{0}''.  Must be in the format: ''Header-Name: header-value''", header);
126         if (isNotEmpty(h[1]))
127            psb.addTo(REST_defaultResponseHeaders, h[0], h[1]);
128      }
129
130      psb.addTo(REST_responseHandlers, a.responseHandlers());
131
132      psb.addTo(REST_converters, a.converters());
133
134      psb.addTo(REST_guards, reverse(a.guards()));
135
136      psb.addTo(REST_children, a.children());
137
138      psb.set(BEAN_beanFilters, merge(ObjectUtils.toType(psb.peek(BEAN_beanFilters), Object[].class), a.beanFilters()));
139
140      psb.set(BEAN_pojoSwaps, merge(ObjectUtils.toType(psb.peek(BEAN_pojoSwaps), Object[].class), a.pojoSwaps()));
141
142      psb.addTo(REST_paramResolvers, a.paramResolvers());
143
144      if (a.serializerListener() != SerializerListener.Null.class)
145         psb.set(SERIALIZER_listener, a.serializerListener());
146
147      if (a.parserListener() != ParserListener.Null.class)
148         psb.set(PARSER_listener, a.parserListener());
149
150      s = string(a.uriContext());
151      if (isNotEmpty(s))
152         psb.set(REST_uriContext, s);
153
154      s = string(a.uriAuthority());
155      if (isNotEmpty(s))
156         psb.set(REST_uriAuthority, s);
157
158      s = string(a.uriRelativity());
159      if (isNotEmpty(s))
160         psb.set(REST_uriRelativity, s);
161
162      s = string(a.uriResolution());
163      if (isNotEmpty(s))
164         psb.set(REST_uriResolution, s);
165
166      for (String mapping : a.staticFiles()) {
167         try {
168            for (StaticFileMapping sfm : reverseIterable(StaticFileMapping.parse(c.inner(), string(mapping))))
169               psb.addTo(REST_staticFiles, sfm);
170         } catch (ParseException e) {
171            throw new ConfigException(e, "Invalid @Resource(staticFiles) value on class ''{0}''", c);
172         }
173      }
174
175      if (! a.messages().isEmpty())
176         psb.addTo(REST_messages, new MessageBundleLocation(c.inner(), string(a.messages())));
177
178      for (String header : strings(a.staticFileResponseHeaders())) {
179         String[] h = RestUtils.parseHeader(header);
180         if (h == null)
181            throw new FormattedRuntimeException("Invalid static file response header specified: ''{0}''.  Must be in the format: ''Header-Name: header-value''", header);
182         if (isNotEmpty(h[1]))
183            psb.addTo(REST_staticFileResponseHeaders, h[0], h[1]);
184      }
185
186      if (! a.useClasspathResourceCaching().isEmpty())
187         psb.set(REST_useClasspathResourceCaching, bool(a.useClasspathResourceCaching()));
188
189      if (a.classpathResourceFinder() != ClasspathResourceFinder.Null.class)
190         psb.set(REST_classpathResourceFinder, a.classpathResourceFinder());
191
192      if (! a.path().isEmpty())
193         psb.set(REST_path, trimLeadingSlash(string(a.path())));
194
195      if (! a.clientVersionHeader().isEmpty())
196         psb.set(REST_clientVersionHeader, string(a.clientVersionHeader()));
197
198      if (a.resourceResolver() != RestResourceResolver.Null.class)
199         psb.set(REST_resourceResolver, a.resourceResolver());
200
201      if (a.logger() != RestLogger.Null.class)
202         psb.set(REST_logger, a.logger());
203
204      if (a.callLogger() != RestCallLogger.Null.class)
205         psb.set(REST_callLogger, a.callLogger());
206
207      if (! AnnotationUtils.empty(a.logging())) {
208         Logging al = a.logging();
209         ObjectMap m = new ObjectMap(psb.peek(ObjectMap.class, REST_callLoggerConfig));
210
211         if (! al.useStackTraceHashing().isEmpty())
212            m.append("useStackTraceHashing", bool(al.useStackTraceHashing()));
213
214         if (! al.stackTraceHashingTimeout().isEmpty())
215            m.append("stackTraceHashingTimeout", integer(al.stackTraceHashingTimeout(), "@Logging(stackTraceHashingTimeout)"));
216
217         if (! al.disabled().isEmpty())
218            m.append("disabled", enablement(al.disabled()));
219
220         if (! al.level().isEmpty())
221            m.append("level", level(al.level(), "@Logging(level)"));
222
223         if (al.rules().length > 0) {
224            ObjectList ol = new ObjectList();
225            for (LoggingRule a2 : al.rules()) {
226               ObjectMap m2 = new ObjectMap();
227
228               if (! a2.codes().isEmpty())
229                  m2.append("codes", string(a2.codes()));
230
231               if (! a2.exceptions().isEmpty())
232                  m2.append("exceptions", string(a2.exceptions()));
233
234               if (! a2.debugOnly().isEmpty())
235                   m2.append("debugOnly", bool(a2.debugOnly()));
236
237               if (! a2.level().isEmpty())
238                  m2.append("level", level(a2.level(), "@LoggingRule(level)"));
239
240               if (! a2.req().isEmpty())
241                  m2.append("req", string(a2.req()));
242
243               if (! a2.res().isEmpty())
244                  m2.append("res", string(a2.res()));
245
246               if (! a2.verbose().isEmpty())
247                  m2.append("verbose", bool(a2.verbose()));
248
249               if (! a2.disabled().isEmpty())
250                  m2.append("disabled", bool(a2.disabled()));
251
252               ol.add(m2);
253            }
254            m.put("rules", ol.appendAll(m.getObjectList("rules")));
255         }
256
257         psb.set(REST_callLoggerConfig, m);
258      }
259
260      if (a.callHandler() != RestCallHandler.Null.class)
261         psb.set(REST_callHandler, a.callHandler());
262
263      if (a.infoProvider() != RestInfoProvider.Null.class)
264         psb.set(REST_infoProvider, a.infoProvider());
265
266      if (! a.allowBodyParam().isEmpty())
267         psb.set(REST_allowBodyParam, bool(a.allowBodyParam()));
268
269      if (! a.allowedHeaderParams().isEmpty())
270         psb.set(REST_allowedHeaderParams, string(a.allowedHeaderParams()));
271
272      if (! a.allowedMethodHeaders().isEmpty())
273         psb.set(REST_allowedMethodHeaders, string(a.allowedMethodHeaders()));
274
275      if (! a.allowedMethodParams().isEmpty())
276         psb.set(REST_allowedMethodParams, string(a.allowedMethodParams()));
277
278      if (! a.allowHeaderParams().isEmpty())
279         psb.set(REST_allowHeaderParams, bool(a.allowHeaderParams()));
280
281      if (! a.renderResponseStackTraces().isEmpty())
282         psb.set(REST_renderResponseStackTraces, bool(a.renderResponseStackTraces()));
283
284      if (! a.useStackTraceHashes().isEmpty())
285         psb.set(REST_useStackTraceHashes, bool(a.useStackTraceHashes()));
286
287      if (! a.defaultCharset().isEmpty())
288         psb.set(REST_defaultCharset, string(a.defaultCharset()));
289
290      if (! a.maxInput().isEmpty())
291         psb.set(REST_maxInput, string(a.maxInput()));
292
293      if (! a.debug().isEmpty()) {
294         psb.set(REST_debug, a.debug());
295      }
296
297      psb.addTo(REST_mimeTypes, strings(a.mimeTypes()));
298
299      if (! a.rolesDeclared().isEmpty())
300         psb.addTo(REST_rolesDeclared, strings(a.rolesDeclared()));
301
302      if (! a.roleGuard().isEmpty())
303         psb.addTo(REST_roleGuard, string(a.roleGuard()));
304
305      HtmlDoc hd = a.htmldoc();
306      new HtmlDocBuilder(psb).process(hd);
307      for (Class<? extends Widget> wc : hd.widgets()) {
308         Widget w = castOrCreate(Widget.class, wc);
309         psb.addTo(REST_widgets, w);
310         psb.addTo(HTMLDOC_script, "$W{"+w.getName()+".script}");
311         psb.addTo(HTMLDOC_script, "$W{"+w.getName()+".style}");
312      }
313   }
314
315   private String trimLeadingSlash(String value) {
316      if (startsWith(value, '/'))
317         return value.substring(1);
318      return value;
319   }
320
321   private Enablement enablement(String in) {
322      return Enablement.fromString(string(in));
323   }
324
325   private Level level(String in, String loc) {
326      try {
327         return Level.parse(string(in).toUpperCase());
328      } catch (Exception e) {
329         throw new ConfigException("Invalid syntax for level on annotation @RestResource({0}): {1}", loc, in);
330      }
331   }
332}