001/** 002 * Copyright 2014 Tampere University of Technology, Pori Department 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package core.tut.pori.context; 017 018import java.lang.annotation.Annotation; 019import java.lang.reflect.Constructor; 020import java.lang.reflect.InvocationTargetException; 021import java.lang.reflect.Method; 022import java.util.Arrays; 023import java.util.Date; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Map; 028 029import org.apache.commons.lang3.exception.ExceptionUtils; 030import org.apache.commons.lang3.tuple.Pair; 031import org.apache.log4j.Logger; 032import org.springframework.beans.BeansException; 033import org.springframework.context.support.ClassPathXmlApplicationContext; 034 035import core.tut.pori.http.Definitions; 036import core.tut.pori.http.Response; 037import core.tut.pori.http.ServiceRequest; 038import core.tut.pori.http.Response.Status; 039import core.tut.pori.http.annotations.HTTPAuthenticationParameter; 040import core.tut.pori.http.annotations.HTTPHeaderParameter; 041import core.tut.pori.http.annotations.HTTPMethodParameter; 042import core.tut.pori.http.annotations.HTTPService; 043import core.tut.pori.http.annotations.HTTPServiceMethod; 044import core.tut.pori.http.headers.HTTPHeader; 045import core.tut.pori.http.parameters.AuthenticationParameter; 046import core.tut.pori.http.parameters.HTTPParameter; 047import core.tut.pori.users.UserIdentity; 048import core.tut.pori.utils.StringUtils; 049 050/** 051 * This class initializes and handles the Service registry. 052 * 053 * Instances of the Service objects can be retrieved using this class, though generally the instances do not have to be called directly by any class or object. 054 * 055 * The service initialization happens automatically based on the rest servlet configuration and annotated classes, 056 * the services are automatically invoked when called through the associated web application URI paths. 057 * 058 * One should not initialize this handler directly, as an instantiated version is available from ServiceInitializer. 059 */ 060public class ServiceHandler { 061 private static final Logger LOGGER = Logger.getLogger(ServiceHandler.class); 062 private static final String SERVLET_CONFIGURATION_FILE = "rest-servlet.xml"; 063 private ClassPathXmlApplicationContext _context = null; 064 private Map<String, Service> _services = null; // service name-service map 065 066 /** 067 * 068 * @throws BeansException on failure 069 */ 070 public ServiceHandler() throws BeansException{ 071 initialize(); 072 } 073 074 /** 075 * 076 * @throws BeansException on failure 077 */ 078 private void initialize() throws BeansException{ 079 LOGGER.debug("Initializing handler..."); 080 Date started = new Date(); 081 _context = new ClassPathXmlApplicationContext(core.tut.pori.properties.SystemProperty.CONFIGURATION_FILE_PATH+SERVLET_CONFIGURATION_FILE); 082 083 LOGGER.debug("Class Path XML Context initialized in "+StringUtils.getDurationString(started, new Date())); 084 085 Map<String, Object> services = _context.getBeansWithAnnotation(HTTPService.class); 086 int count = services.size(); 087 LOGGER.info("Found "+count+" service(s)."); 088 _services = new HashMap<>(count); 089 090 for(Iterator<Object> iter = services.values().iterator();iter.hasNext();){ 091 addService(iter.next()); 092 } 093 094 LOGGER.debug("Service Handler initialized in "+StringUtils.getDurationString(started, new Date())); 095 } 096 097 /** 098 * close this Service handler and release are resources associated with it 099 */ 100 public void close(){ 101 _context.close(); 102 _context = null; 103 _services = null; 104 } 105 106 /** 107 * remove leading and trailing separator / from the name if any are present 108 * 109 * @param name 110 * @return the name or null if name was invalid 111 */ 112 private String clearSeparators(String name) { 113 if(org.apache.commons.lang3.StringUtils.isBlank(name)){ 114 return null; 115 } 116 117 boolean startsWith = name.startsWith(Definitions.SEPARATOR_URI_PATH); 118 boolean endsWith = name.endsWith(Definitions.SEPARATOR_URI_PATH); 119 if(startsWith || endsWith){ 120 name = name.substring((startsWith ? 1 : 0), (endsWith ? name.length()-1 : name.length())); // chop from beginning and end if required 121 if(org.apache.commons.lang3.StringUtils.isBlank(name)){ 122 name = null; 123 } 124 } 125 return name; 126 } 127 128 /** 129 * Invoke a service described by the given request. 130 * 131 * @param serviceRequest 132 * @return a Response object with status notifying about the result of the invocation. 133 */ 134 public Response invoke(ServiceRequest serviceRequest){ 135 if(!ServiceRequest.isValid(serviceRequest)){ 136 return new Response(Status.BAD_REQUEST); 137 } 138 String serviceName = serviceRequest.getServiceName(); 139 Service service = _services.get(serviceName); 140 if(service == null){ 141 return new Response(Status.NOT_FOUND, "No such service: "+serviceName); 142 } 143 144 String methodName = serviceRequest.getMethodName(); 145 String httpMethod = serviceRequest.getHttpMethod(); 146 ServiceMethod method = service.getMethod(httpMethod, methodName); 147 if(method == null){ 148 return new Response(Status.NOT_FOUND, "No such method: "+httpMethod+" "+methodName); 149 } 150 151 int parameterCount = method.getParameterCount(); 152 if(parameterCount < 1){ // no required arguments 153 return invoke(method.getMethod(), null, method.getReturnType(), service.getServiceObject()); 154 } 155 156 Object[] args = new Object[parameterCount]; 157 158 try { // catch instantation exceptions, which should never really happen 159 AuthParameter authParam = method.getAuthParam(); 160 if(!setAuthParam(authParam, args, serviceRequest)){ // check if authentication is required 161 Response response = method.getReturnType().newInstance(); 162 if(authParam.isShowLoginPrompt()){ 163 response.setStatus(Status.UNAUTHORIZED); 164 }else{ 165 response.setStatus(Status.FORBIDDEN); 166 } 167 return response; 168 } 169 170 try{ // check if the given parameters are valid 171 setHeaderParams(args, method.getHeaderParams(), serviceRequest); 172 setMethodParams(args, method.getMethodParams(), serviceRequest); 173 }catch(IllegalArgumentException ex){ 174 LOGGER.debug(ex, ex); 175 Response response = method.getReturnType().newInstance(); 176 response.setStatus(Status.BAD_REQUEST); 177 response.setMessage(ex.getMessage()); 178 return response; 179 } 180 } catch (InstantiationException | IllegalAccessException ex) { // should not happen 181 LOGGER.error(ExceptionUtils.getStackTrace(ex)); 182 return new Response(Status.INTERNAL_SERVER_ERROR); 183 } 184 185 return invoke(method.getMethod(), args, method.getReturnType(), service.getServiceObject()); 186 } 187 188 /** 189 * 190 * @param method 191 * @param methodArgs 192 * @param returnType 193 * @param serviceObject 194 * @return response 195 */ 196 private Response invoke(Method method, Object[] methodArgs, Class<? extends Response> returnType, Object serviceObject){ 197 try{ 198 try { 199 Object retval = method.invoke(serviceObject, methodArgs); 200 if(retval == null){ 201 return returnType.newInstance(); // return default OK for void 202 }else{ 203 return (Response) retval; // this is checked by the initializer to be the only possible return type 204 } 205 } catch (InvocationTargetException ex) { 206 Throwable cause = ex.getCause(); 207 LOGGER.error(ex, cause); // print exception and the actual cause 208 Response response = returnType.newInstance(); 209 if(cause instanceof IllegalArgumentException){ // accept as bad request 210 response.setStatus(Status.BAD_REQUEST); 211 response.setMessage(cause.getMessage()); 212 }else{ // this should have been caught by the implementation 213 response.setStatus(Status.INTERNAL_SERVER_ERROR); 214 } 215 return response; 216 } 217 } catch (InstantiationException | IllegalAccessException | IllegalArgumentException ex) { // should not happen 218 LOGGER.error(ExceptionUtils.getStackTrace(ex)); 219 return new Response(Status.INTERNAL_SERVER_ERROR); 220 } 221 } 222 223 /** 224 * 225 * @param methodArgs methodArgs argument list for the method to be called, the parameter will be set to this array to its correct index if needed 226 * @param params can be null 227 * @param serviceRequest 228 * @throws IllegalArgumentException on bad request argument 229 */ 230 private void setMethodParams(Object[] methodArgs, Map<String,MethodParameter> params, ServiceRequest serviceRequest) throws IllegalArgumentException{ 231 if(params == null){ 232 return; 233 } 234 235 Map<String,List<String>> paramMap = serviceRequest.getRawParameters(); 236 237 try { 238 for(Map.Entry<String, MethodParameter> e : params.entrySet()){ 239 String paramName = e.getKey(); 240 MethodParameter param = e.getValue(); 241 HTTPParameter p = param.getParameter().newInstance(); 242 p.setParameterName(paramName); 243 if(param.isBodyParameter()){ 244 p.initialize(serviceRequest.getBody()); 245 }else{ 246 List<String> values = (paramMap == null ? null : paramMap.get(paramName)); 247 if(param.isRequired() && values == null){ 248 throw new IllegalArgumentException("Requested parameter "+paramName+" was not found."); 249 } 250 251 if(values == null){ 252 List<String> defaultValues = param.getDefaultValues(); 253 if(defaultValues != null){ // if default value has been given 254 if(defaultValues.size() == 1){ 255 p.initializeRaw(defaultValues.get(0)); 256 }else{ 257 p.initializeRaw(defaultValues); 258 } 259 } 260 }else if(values.size() == 1){ 261 p.initializeRaw(values.get(0)); 262 }else{ 263 p.initializeRaw(values); 264 } 265 } 266 methodArgs[param.getParameterIndex()] = p; 267 } 268 } catch (InstantiationException | IllegalAccessException ex) { // this should not happen 269 LOGGER.error(ex, ex); 270 throw new IllegalArgumentException("Failed to parse parameters."); 271 } 272 } 273 274 /** 275 * 276 * @param methodArgs argument list for the method to be called, the parameter will be set to this array to its correct index if needed 277 * @param params can be null 278 * @param serviceRequest 279 * @throws IllegalArgumentException on bad request argument 280 */ 281 private void setHeaderParams(Object[] methodArgs, Map<String, HeaderParameter> params, ServiceRequest serviceRequest) throws IllegalArgumentException{ 282 if(params == null){ 283 return; 284 } 285 286 try { 287 for(Map.Entry<String, HeaderParameter> e : params.entrySet()){ 288 String headerName = e.getKey(); 289 HeaderParameter param = e.getValue(); 290 String value = serviceRequest.getHeaderValue(headerName); 291 if(param.isRequired() && value == null){ 292 throw new IllegalArgumentException("Requested Header field "+headerName+" was not found."); 293 } 294 295 HTTPHeader header = param.getParameter().newInstance(); 296 header.setName(headerName); 297 if(value == null){ 298 value = param.getDefaultValue(); 299 } 300 header.setValue(value); 301 methodArgs[param.getParameterIndex()] = header; 302 } 303 } catch (InstantiationException | IllegalAccessException ex) { // should not happen 304 LOGGER.error(ex, ex); 305 throw new IllegalArgumentException("Failed to parse HTTP headers."); 306 } 307 } 308 309 /** 310 * helper method for setting the authentication parameter to method arguments 311 * 312 * @param authParam can be null 313 * @param methodArgs argument list for the method to be called, the parameter will be set to this array to its correct index if needed 314 * @param serviceRequest 315 * @return true on success (=user was authenticated, and authentication was required) 316 */ 317 private boolean setAuthParam(AuthParameter authParam, Object[] methodArgs, ServiceRequest serviceRequest){ 318 if(authParam != null){ // authentication is at least requested 319 UserIdentity authenticatedUser = serviceRequest.getAuthenticatedUser(); 320 if(authParam.isRequired() && authenticatedUser == null){ // authentication is required, but not provided 321 return false; 322 }else{ 323 try { 324 AuthenticationParameter p = authParam.getParameter().newInstance(); 325 p.setUserIdentity(authenticatedUser); 326 p.setSession(serviceRequest.getSession()); 327 methodArgs[authParam.getParameterIndex()] = p; 328 } catch (InstantiationException | IllegalAccessException ex) { // this should not happen... 329 LOGGER.error(ex, ex); 330 return false; // ...but if it does, do not allow further user access 331 } 332 } 333 } 334 return true; 335 } 336 337 /** 338 * 339 * @param object 340 * @throws IllegalArgumentException 341 */ 342 private void addService(Object object) throws IllegalArgumentException { 343 Class<?> cls = object.getClass(); 344 HTTPService serviceAnnotation = cls.getAnnotation(HTTPService.class); 345 346 Service service = new Service(object); 347 Method[] methods = cls.getMethods(); 348 for(int i=0;i<methods.length;++i){ 349 HTTPServiceMethod methodAnnotation = methods[i].getAnnotation(HTTPServiceMethod.class); 350 if(methodAnnotation != null){ 351 String[] am = methodAnnotation.acceptedMethods(); 352 if(am == null || am.length < 1){ 353 throw new IllegalArgumentException("The method "+methods[i].toString()+" does not allow any of HTTP Methods."); 354 } 355 for(int j=0;j<am.length;++j){ // separate to different pairs based on HTTP method 356 service.addMethod(methods[i],clearSeparators(methodAnnotation.name()), am[j]); 357 } 358 } // if 359 } // for 360 if(methods.length < 1){ 361 LOGGER.warn("Ignored service "+cls.toString()+": no valid methods defined."); 362 return; 363 } 364 365 String name = clearSeparators(serviceAnnotation.name()); 366 if(name == null){ 367 throw new IllegalArgumentException("Invalid service name for "+cls.toString()); 368 }else if(_services.containsKey(name)){ 369 throw new IllegalArgumentException("Duplicate service name "+name+" for "+cls.toString()); 370 }else{ 371 _services.put(name, service); 372 } 373 } 374 375 /** 376 * Defines a single service invokable by the handler. 377 * 378 */ 379 private static class Service{ 380 private Map<Pair<String, String>, ServiceMethod> _methods = null; // method name/httpMethod-method map, where httpMethod is the HTTP verb, e.g. POST or GET 381 private Object _service = null; // service object represented as spring bean 382 383 /** 384 * 385 * @param service 386 */ 387 public Service(Object service){ 388 _service = service; 389 _methods = new HashMap<>(); 390 } 391 392 /** 393 * 394 * @param method 395 * @param methodName 396 * @param httpMethod e.g. POST or GET 397 * @throws IllegalArgumentException on bad methodName 398 */ 399 public void addMethod(Method method, String methodName, String httpMethod) throws IllegalArgumentException{ 400 if(methodName == null){ 401 throw new IllegalArgumentException("Invalid methodName for "+method.toString()); 402 }else{ 403 Pair<String, String> methodPair = Pair.of(methodName, httpMethod); 404 if(_methods.containsKey(methodPair)){ 405 throw new IllegalArgumentException("Duplicate methodName: "+methodName+" and/or method type "+httpMethod+" for "+method.toString()); 406 }else{ 407 _methods.put(methodPair, new ServiceMethod(method)); 408 } 409 } 410 411 } 412 413 /** 414 * 415 * @param httpMethod 416 * @param methodName 417 * @return the method or null if none found 418 */ 419 public ServiceMethod getMethod(String httpMethod, String methodName){ 420 return _methods.get(Pair.of(methodName, httpMethod)); 421 } 422 423 /** 424 * 425 * @return the service object 426 */ 427 public Object getServiceObject(){ 428 return _service; 429 } 430 } // class Service 431 432 /** 433 * Defines a single method invokable through a Service. 434 * 435 */ 436 private static class ServiceMethod{ 437 private AuthParameter _authParam = null; 438 private Map<String,HeaderParameter> _headerParams = null; // parameter name-parameter_type map 439 private Method _method = null; 440 private Map<String,MethodParameter> _methodParams = null; // parameter name-parameter_type map 441 private int _parameterCount = 0; 442 private Class<? extends Response> _returnType = null; 443 444 /** 445 * 446 * @param method 447 * @throws IllegalArgumentException on bad Method 448 */ 449 public ServiceMethod(Method method) throws IllegalArgumentException{ 450 _method = method; 451 initialize(); 452 } 453 454 /** 455 * 456 * @throws IllegalArgumentException on bad parameter 457 */ 458 @SuppressWarnings("unchecked") 459 private void initialize() throws IllegalArgumentException{ 460 Class<?> responseClass= _method.getReturnType(); 461 if(responseClass.equals(Void.TYPE)){ 462 _returnType = Response.class; 463 }else if(!Response.class.isAssignableFrom(responseClass)){ // check for valid return type 464 throw new IllegalArgumentException("Return type not "+Void.TYPE.toString()+" or "+Response.class.toString()+" for "+_method.toString()); 465 }else{ 466 _returnType = (Class<? extends Response>) responseClass; 467 } 468 469 Annotation[][] annotations = _method.getParameterAnnotations(); // get annotation "map" 470 if(annotations.length < 1){ // no parameters 471 return; 472 } 473 _methodParams = new HashMap<>(); 474 _headerParams = new HashMap<>(); 475 476 Class<?>[] paramTypes = _method.getParameterTypes(); // get types of the parameters 477 boolean bodyParameterGiven = false; 478 for(int i=0;i<annotations.length;++i){ // go through types 479 if(AuthenticationParameter.class.isAssignableFrom(paramTypes[i])){ // check for authentication parameter 480 if(_authParam != null){ 481 throw new IllegalArgumentException("Duplicate "+AuthenticationParameter.class.toString()+" in "+_method.toString()); 482 } 483 484 HTTPAuthenticationParameter parameterAnnotation = null; 485 for(Annotation annotation : annotations[i]){ // check that the required annotation is present 486 if(annotation.annotationType() == HTTPAuthenticationParameter.class){ 487 parameterAnnotation = (HTTPAuthenticationParameter)annotation; 488 break; 489 } 490 } 491 if(parameterAnnotation == null){ // the annotation is missing 492 throw new IllegalArgumentException("Annotation "+HTTPAuthenticationParameter.class.toString()+" is missing from: "+paramTypes[i].toString()+" in "+_method.toString()); 493 } 494 495 _authParam = new AuthParameter((Class<? extends AuthenticationParameter>) paramTypes[i], i, parameterAnnotation.required(), parameterAnnotation.showLoginPrompt()); // not really "unchecked" cast 496 }else if(HTTPParameter.class.isAssignableFrom(paramTypes[i])){ // if this is a http parameter 497 HTTPMethodParameter parameterAnnotation = null; 498 for(Annotation annotation : annotations[i]){ // check that the required annotation is present 499 if(annotation.annotationType() == HTTPMethodParameter.class){ 500 parameterAnnotation = (HTTPMethodParameter)annotation; 501 break; 502 } 503 } 504 if(parameterAnnotation == null){ // the annotation is missing 505 throw new IllegalArgumentException("Annotation "+HTTPMethodParameter.class.toString()+" is missing from: "+paramTypes[i].toString()+" in "+_method.toString()); 506 } 507 508 boolean isBody = parameterAnnotation.bodyParameter(); 509 if(isBody){ 510 if(bodyParameterGiven){ 511 throw new IllegalArgumentException("Duplicate HTTP body paramater in "+_method.toString()); 512 }else{ 513 bodyParameterGiven = true; 514 } 515 } 516 517 String name = parameterAnnotation.name(); 518 if(org.apache.commons.lang3.StringUtils.isBlank(name)){ 519 throw new IllegalArgumentException("Invalid parameter name "+name+" in "+_method.toString()); 520 }else if(_methodParams.containsKey(name)){ 521 throw new IllegalArgumentException("Duplicate parameter name "+name+" in "+_method.toString()); 522 } 523 524 _methodParams.put(name, new MethodParameter(parameterAnnotation.defaultValue(), isBody, (Class<? extends HTTPParameter>) paramTypes[i], i,parameterAnnotation.required())); // not really "unchecked" cast 525 }else if(HTTPHeader.class.isAssignableFrom(paramTypes[i])){ // this is a header 526 HTTPHeaderParameter parameterAnnotation = null; 527 for(Annotation annotation : annotations[i]){ // check that the required annotation is present 528 if(annotation.annotationType() == HTTPHeaderParameter.class){ 529 parameterAnnotation = (HTTPHeaderParameter)annotation; 530 break; 531 } 532 } 533 if(parameterAnnotation == null){ // the annotation is missing 534 throw new IllegalArgumentException("Annotation "+HTTPHeaderParameter.class.toString()+" is missing from: "+paramTypes[i].toString()+" in "+_method.toString()); 535 } 536 537 String name = parameterAnnotation.name(); 538 if(org.apache.commons.lang3.StringUtils.isBlank(name)){ 539 throw new IllegalArgumentException("Invalid header name "+name+" in "+_method.toString()); 540 }else if(_headerParams.containsKey(name)){ 541 throw new IllegalArgumentException("Duplicate header name "+name+" in "+_method.toString()); 542 } 543 544 _headerParams.put(name, new HeaderParameter(parameterAnnotation.defaultValue(), (Class<? extends HTTPHeader>) paramTypes[i], i, parameterAnnotation.required())); // not really "unchecked" cast 545 }else{ // unknown type 546 throw new IllegalArgumentException(paramTypes[i].toString()+" is not subclass of "+HTTPParameter.class.toString()+" in "+_method.toString()); 547 } 548 549 Constructor<?>[] constructors = paramTypes[i].getConstructors(); 550 for(int j=0;j<constructors.length;++j){ // check that no-args constructor is present for the argument 551 if(constructors[j].getParameterTypes().length < 1){ 552 constructors = null; 553 break; 554 } 555 } 556 if(constructors != null){ 557 throw new IllegalArgumentException("No no-args constructor available for the type: "+paramTypes[i].toString()+" in "+_method.toString()); 558 } 559 } // for types 560 if(_headerParams.isEmpty()){ 561 _headerParams = null; // empty list not needed 562 } 563 if(_methodParams.isEmpty()){ 564 _methodParams = null; // empty list not needed 565 } 566 _parameterCount = annotations.length; // get the argument count 567 } 568 569 /** 570 * @return the method 571 */ 572 public Method getMethod() { 573 return _method; 574 } 575 576 /** 577 * @return the methodParams 578 */ 579 public Map<String, MethodParameter> getMethodParams() { 580 return _methodParams; 581 } 582 583 /** 584 * @return the headerParams 585 */ 586 public Map<String, HeaderParameter> getHeaderParams() { 587 return _headerParams; 588 } 589 590 /** 591 * @return the authParam 592 */ 593 public AuthParameter getAuthParam() { 594 return _authParam; 595 } 596 597 /** 598 * @return the parameter count 599 */ 600 public int getParameterCount() { 601 return _parameterCount; 602 } 603 604 /** 605 * @return the returnType 606 */ 607 public Class<? extends Response> getReturnType() { 608 return _returnType; 609 } 610 } // class ServiceMethod 611 612 /** 613 * Method parameter base class 614 * 615 */ 616 private static abstract class Parameter{ 617 private int _parameterIndex = -1; 618 619 /** 620 * 621 * @param parameterIndex the index of this parameter in the method declaration 622 */ 623 public Parameter(int parameterIndex){ 624 _parameterIndex = parameterIndex; 625 } 626 627 /** 628 * @return the parameterIndex 629 */ 630 public int getParameterIndex() { 631 return _parameterIndex; 632 } 633 } // class Parameter 634 635 /** 636 * Defines a single method parameter assigned to service method. 637 * 638 */ 639 private static class MethodParameter extends Parameter{ 640 private List<String> _defaultValues = null; 641 private boolean _isBodyParameter = false; 642 private Class<? extends HTTPParameter> _parameter = null; // for instantiating new classes for parsing process, if null, null will be returned as value 643 private boolean _required = false; 644 645 /** 646 * 647 * @param defaultValue 648 * @param isBodyParameter 649 * @param parameterClass 650 * @param parameterIndex 651 * @param required 652 */ 653 public MethodParameter(String defaultValue, boolean isBodyParameter, Class<? extends HTTPParameter> parameterClass, int parameterIndex, boolean required){ 654 super(parameterIndex); 655 _parameter = parameterClass; 656 if(org.apache.commons.lang3.StringUtils.isBlank(defaultValue)){ 657 _defaultValues = null; 658 }else{ 659 _defaultValues = Arrays.asList(org.apache.commons.lang3.StringUtils.split(defaultValue, Definitions.SEPARATOR_URI_QUERY_PARAM_VALUES)); 660 } 661 _required = required; 662 _isBodyParameter = isBodyParameter; 663 } 664 665 /** 666 * @return the parameter 667 */ 668 public Class<? extends HTTPParameter> getParameter() { 669 return _parameter; 670 } 671 672 /** 673 * @return the defaultValue or null if none available 674 */ 675 public List<String> getDefaultValues() { 676 return _defaultValues; 677 } 678 679 /** 680 * @return the required 681 */ 682 public boolean isRequired() { 683 return _required; 684 } 685 686 /** 687 * @return the isBodyParameter 688 */ 689 public boolean isBodyParameter() { 690 return _isBodyParameter; 691 } 692 } // class MethodParamater 693 694 /** 695 * A special authentication parameter, which defines whether user authentication should be required or not upon method invocation. 696 * 697 */ 698 private static class AuthParameter extends Parameter{ 699 private Class<? extends AuthenticationParameter> _parameter = null; 700 private boolean _required = false; 701 private boolean _showLoginPrompt = false; 702 703 /** 704 * 705 * @param parameter 706 * @param parameterIndex 707 * @param required 708 * @param showLoginPrompt 709 */ 710 public AuthParameter(Class<? extends AuthenticationParameter> parameter, int parameterIndex, boolean required, boolean showLoginPrompt){ 711 super(parameterIndex); 712 _parameter = parameter; 713 _required = required; 714 _showLoginPrompt = showLoginPrompt; 715 } 716 717 /** 718 * @return the parameter 719 */ 720 public Class<? extends AuthenticationParameter> getParameter() { 721 return _parameter; 722 } 723 724 /** 725 * @return the required 726 */ 727 public boolean isRequired() { 728 return _required; 729 } 730 731 /** 732 * @return the showLoginPrompt 733 */ 734 public boolean isShowLoginPrompt() { 735 return _showLoginPrompt; 736 } 737 } // class AuthParameter 738 739 /** 740 * Defines a header parameter inside a Service method. 741 * 742 */ 743 private static class HeaderParameter extends Parameter{ 744 private String _defaultValue = null; 745 private Class<? extends HTTPHeader> _parameter = null; 746 private boolean _required = false; 747 748 /** 749 * 750 * @param defaultValue 751 * @param parameter 752 * @param parameterIndex 753 * @param required 754 */ 755 public HeaderParameter(String defaultValue, Class<? extends HTTPHeader> parameter, int parameterIndex, boolean required){ 756 super(parameterIndex); 757 _parameter = parameter; 758 _defaultValue = defaultValue; 759 if(org.apache.commons.lang3.StringUtils.isBlank(_defaultValue)){ 760 _defaultValue = null; 761 } 762 _required = required; 763 } 764 765 /** 766 * @return the parameter 767 */ 768 public Class<? extends HTTPHeader> getParameter() { 769 return _parameter; 770 } 771 772 /** 773 * @return the defaultValue 774 */ 775 public String getDefaultValue() { 776 return _defaultValue; 777 } 778 779 /** 780 * @return the required 781 */ 782 public boolean isRequired() { 783 return _required; 784 } 785 } // class HeaderParameter 786}