summaryrefslogtreecommitdiffstats
path: root/ms/controllerblueprints/application/src/main
diff options
context:
space:
mode:
authorDan Timoney <dt5972@att.com>2018-09-04 15:14:31 +0000
committerGerrit Code Review <gerrit@onap.org>2018-09-04 15:14:31 +0000
commit9abed7f23417e24039d463f84156c1d9fef672f7 (patch)
tree5f8cc884094cac2dbd1fd02d64325dc5e45d457f /ms/controllerblueprints/application/src/main
parentbae35a20cafabf78672db065e41f4018c619e863 (diff)
parent74a62bea98248a496ae032ed694e19573cd98d0b (diff)
Merge "Controller Blueprints Microservice"
Diffstat (limited to 'ms/controllerblueprints/application/src/main')
-rw-r--r--ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ApplicationExceptionHandler.java16
-rw-r--r--ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ControllerBluprintsApplication.java2
-rw-r--r--ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/CorsConfig.java55
-rw-r--r--ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/SwaggerConfig.java97
-rw-r--r--ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/WebConfig.java1
-rw-r--r--ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/filters/ApplicationLoggingFilter.java81
-rw-r--r--ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/filters/CorsFilter.java61
7 files changed, 253 insertions, 60 deletions
diff --git a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ApplicationExceptionHandler.java b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ApplicationExceptionHandler.java
index 0a403b8c..6e9dcd7f 100644
--- a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ApplicationExceptionHandler.java
+++ b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ApplicationExceptionHandler.java
@@ -22,6 +22,9 @@ import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintException;
import org.onap.ccsdk.apps.controllerblueprints.service.common.ErrorMessage;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
@@ -32,17 +35,26 @@ import org.springframework.web.context.request.WebRequest;
@SuppressWarnings("unused")
public class ApplicationExceptionHandler {
private static EELFLogger log = EELFManager.getInstance().getLogger(ApplicationExceptionHandler.class);
+
@ExceptionHandler(Exception.class)
public final ResponseEntity<ErrorMessage> handleAllExceptions(Exception ex, WebRequest request) {
log.error("Application Exception", ex);
- ErrorMessage exceptionResponse = new ErrorMessage( ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getLocalizedMessage());
+ ErrorMessage exceptionResponse = new ErrorMessage(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getLocalizedMessage());
return new ResponseEntity<>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
+ @ExceptionHandler({HttpMessageNotReadableException.class, MethodArgumentNotValidException.class,
+ HttpRequestMethodNotSupportedException.class})
+ public final ResponseEntity<ErrorMessage> handleBadRequest(Exception ex, WebRequest request) {
+ log.error("Bad Request Exception", ex);
+ ErrorMessage exceptionResponse = new ErrorMessage(ex.getMessage(), HttpStatus.BAD_REQUEST.value(), ex.getLocalizedMessage());
+ return new ResponseEntity<>(exceptionResponse, HttpStatus.BAD_REQUEST);
+ }
+
@ExceptionHandler(BluePrintException.class)
public final ResponseEntity<ErrorMessage> handleBlueprintException(BluePrintException ex, WebRequest request) {
log.error("Application Blueprint Exception", ex);
- ErrorMessage exceptionResponse = new ErrorMessage( ex.getMessage(), ex.getCode(), ex.getLocalizedMessage());
+ ErrorMessage exceptionResponse = new ErrorMessage(ex.getMessage(), ex.getCode(), ex.getLocalizedMessage());
return new ResponseEntity<>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
diff --git a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ControllerBluprintsApplication.java b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ControllerBluprintsApplication.java
index 447e1966..6b0efd87 100644
--- a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ControllerBluprintsApplication.java
+++ b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/ControllerBluprintsApplication.java
@@ -35,7 +35,7 @@ public class ControllerBluprintsApplication {
private static EELFLogger log = EELFManager.getInstance().getLogger(ControllerBluprintsApplication.class);
public static void main(String[] args) {
- log.info("****** Starting Controller Bluprints Application **************");
+ log.info("****** Starting Controlled Blueprints Application ******");
SpringApplication.run(ControllerBluprintsApplication.class, args);
}
diff --git a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/CorsConfig.java b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/CorsConfig.java
deleted file mode 100644
index d00d2c84..00000000
--- a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/CorsConfig.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright © 2017-2018 AT&T Intellectual Property.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onap.ccsdk.apps.controllerblueprints;
-
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.reactive.CorsWebFilter;
-import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
-import java.util.Arrays;
-
-/**
- * CorsConfig.java Purpose: Provide Configuration Generator CorsConfig Information
- *
- * @author Brinda Santh
- * @version 1.0
- */
-@Configuration
-public class CorsConfig {
- /**
- * This is a CORS Implementation for different Orgin GUI to access.
- *
- * @return CorsFilter
- */
- @Bean
- CorsWebFilter corsWebFilter() {
- CorsConfiguration corsConfig = new CorsConfiguration();
- corsConfig.setAllowedOrigins(Arrays.asList("*"));
- corsConfig.setMaxAge(8000L);
- corsConfig.addAllowedMethod("*");
-
- UrlBasedCorsConfigurationSource source =
- new UrlBasedCorsConfigurationSource();
- source.registerCorsConfiguration("/**", corsConfig);
-
- return new CorsWebFilter(source);
- }
-
-
-}
diff --git a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/SwaggerConfig.java b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/SwaggerConfig.java
index 67e3e5d0..cfcccf33 100644
--- a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/SwaggerConfig.java
+++ b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/SwaggerConfig.java
@@ -16,16 +16,30 @@
package org.onap.ccsdk.apps.controllerblueprints;
+import com.google.common.collect.Lists;
+import org.jetbrains.annotations.NotNull;
+import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintConstants;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.builders.ResponseMessageBuilder;
+import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
+import springfox.documentation.service.Header;
+import springfox.documentation.service.ResponseMessage;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* SwaggerConfig
@@ -36,10 +50,23 @@ import java.util.Collections;
@EnableSwagger2
@SuppressWarnings("unused")
public class SwaggerConfig {
+ @Value("${appVersion}")
+ private String appVersion;
+ @Value("${swagger.contact.name}")
+ private String contactName;
+ @Value("${swagger.contact.url}")
+ private String contactUrl;
+ @Value("${swagger.contact.email}")
+ private String contactEmail;
+
@Bean
@SuppressWarnings("unused")
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
+ .globalResponseMessage(RequestMethod.GET, getDefaultGetResponseMessages())
+ .globalResponseMessage(RequestMethod.POST, getDefaultPostResponseMessages())
+ .globalResponseMessage(RequestMethod.PUT, getDefaultPutResponseMessages())
+ .globalResponseMessage(RequestMethod.DELETE, getDefaultDeleteResponseMessages())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
@@ -51,11 +78,77 @@ public class SwaggerConfig {
return new ApiInfo(
"Controller Blueprints API",
"Controller blueprints API for VNF Self Service.",
- "1.0.0",
+ appVersion,
"Terms of service",
- new Contact("Brinda Santh", "www.onap.com", "brindasanth@onap.com"),
+ new Contact(contactName, contactUrl, contactEmail),
"Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", Collections.emptyList());
}
+ private List<ResponseMessage> getDefaultGetResponseMessages() {
+ List<ResponseMessage> defaultResponseMessages = Lists.newArrayList();
+ Map<String, Header> defaultHeaders = getDefaultResponseHeaders();
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.OK, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.BAD_REQUEST, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.UNAUTHORIZED, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.FORBIDDEN, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.NOT_FOUND, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR, defaultHeaders));
+ return defaultResponseMessages;
+ }
+
+ private List<ResponseMessage> getDefaultPostResponseMessages() {
+ List<ResponseMessage> defaultResponseMessages = Lists.newArrayList();
+ Map<String, Header> defaultHeaders = getDefaultResponseHeaders();
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.OK, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.CREATED, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.BAD_REQUEST, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.UNAUTHORIZED, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.FORBIDDEN, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR, defaultHeaders));
+ return defaultResponseMessages;
+ }
+
+ private List<ResponseMessage> getDefaultPutResponseMessages() {
+ List<ResponseMessage> defaultResponseMessages = Lists.newArrayList();
+ Map<String, Header> defaultHeaders = getDefaultResponseHeaders();
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.OK, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.BAD_REQUEST, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.UNAUTHORIZED, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.FORBIDDEN, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR, defaultHeaders));
+ return defaultResponseMessages;
+ }
+
+ private List<ResponseMessage> getDefaultDeleteResponseMessages() {
+ List<ResponseMessage> defaultResponseMessages = Lists.newArrayList();
+ Map<String, Header> defaultHeaders = getDefaultResponseHeaders();
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.OK, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.BAD_REQUEST, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.UNAUTHORIZED, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.FORBIDDEN, defaultHeaders));
+ defaultResponseMessages.add(getResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR, defaultHeaders));
+ return defaultResponseMessages;
+ }
+ private ResponseMessage getResponseBuilder(@NotNull HttpStatus httpStatus, Map<String, Header> defaultHeaders) {
+ ResponseMessageBuilder responseMessageBuilder = new ResponseMessageBuilder();
+ responseMessageBuilder.code(httpStatus.value())
+ .message(httpStatus.getReasonPhrase())
+ .headersWithDescription(defaultHeaders)
+ .build();
+ return responseMessageBuilder.build();
+ }
+
+ private Map<String, Header> getDefaultResponseHeaders() {
+ Map<String, Header> defaultHeaders = new HashMap<>();
+ defaultHeaders.put(BluePrintConstants.RESPONSE_HEADER_TRANSACTION_ID,
+ new Header(BluePrintConstants.RESPONSE_HEADER_TRANSACTION_ID, "Transaction Id", new ModelRef("string")));
+ defaultHeaders.put(BluePrintConstants.RESPONSE_HEADER_LATEST_VERSION,
+ new Header(BluePrintConstants.RESPONSE_HEADER_LATEST_VERSION, "API Latest Version", new ModelRef("string")));
+ defaultHeaders.put(BluePrintConstants.RESPONSE_HEADER_MINOR_VERSION,
+ new Header(BluePrintConstants.RESPONSE_HEADER_MINOR_VERSION, "API Minor Version", new ModelRef("string")));
+ defaultHeaders.put(BluePrintConstants.RESPONSE_HEADER_PATCH_VERSION,
+ new Header(BluePrintConstants.RESPONSE_HEADER_PATCH_VERSION, "API Patch Version", new ModelRef("string")));
+ return defaultHeaders;
+ }
}
diff --git a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/WebConfig.java b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/WebConfig.java
index 1eba97cd..c5cdee62 100644
--- a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/WebConfig.java
+++ b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/WebConfig.java
@@ -26,6 +26,7 @@ import org.springframework.web.reactive.config.WebFluxConfigurationSupport;
* @author Brinda Santh 8/13/2018
*/
@Configuration
+@SuppressWarnings("unused")
public class WebConfig extends WebFluxConfigurationSupport {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
diff --git a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/filters/ApplicationLoggingFilter.java b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/filters/ApplicationLoggingFilter.java
new file mode 100644
index 00000000..9a556e71
--- /dev/null
+++ b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/filters/ApplicationLoggingFilter.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2017-2018 AT&T Intellectual Property.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.ccsdk.apps.controllerblueprints.filters;
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintConstants;
+import org.onap.logging.ref.slf4j.ONAPLogAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * ApplicationLoggingFilter
+ *
+ * @author Brinda Santh 8/14/2018
+ */
+@Component
+@WebFilter(asyncSupported = true, urlPatterns = {"/*"})
+@SuppressWarnings("unused")
+public class ApplicationLoggingFilter implements Filter {
+ private static Logger log = LoggerFactory.getLogger(ApplicationLoggingFilter.class);
+
+ @SuppressWarnings("unused")
+ @Value("${appVersion}")
+ private String appVersion;
+
+ public void doFilter(ServletRequest request,
+ ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse res = (HttpServletResponse) response;
+
+ ONAPLogAdapter onapLogAdapter = new ONAPLogAdapter(log);
+ onapLogAdapter.entering(req);
+
+ String[] tokens = StringUtils.split(appVersion, '.');
+ Preconditions.checkNotNull(tokens, "failed to split application versions");
+ Preconditions.checkArgument(tokens.length == 3, "failed to tokenize application versions");
+ res.addHeader(BluePrintConstants.RESPONSE_HEADER_TRANSACTION_ID, MDC.get("RequestID"));
+ res.addHeader(BluePrintConstants.RESPONSE_HEADER_MINOR_VERSION, tokens[1]);
+ res.addHeader(BluePrintConstants.RESPONSE_HEADER_PATCH_VERSION, tokens[2]);
+ res.addHeader(BluePrintConstants.RESPONSE_HEADER_LATEST_VERSION, appVersion);
+ chain.doFilter(request, response);
+ // Clean the MDC info
+ onapLogAdapter.exiting();
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) {
+
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+} \ No newline at end of file
diff --git a/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/filters/CorsFilter.java b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/filters/CorsFilter.java
new file mode 100644
index 00000000..91cc731d
--- /dev/null
+++ b/ms/controllerblueprints/application/src/main/java/org/onap/ccsdk/apps/controllerblueprints/filters/CorsFilter.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2017-2018 AT&T Intellectual Property.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.ccsdk.apps.controllerblueprints.filters;
+
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+/**
+ * CorsFilter.java Purpose: Provide Configuration Generator CorsFilter Information
+ *
+ * @author Brinda Santh
+ */
+@Component
+@WebFilter(asyncSupported = true, urlPatterns = {"/*"})
+@SuppressWarnings("unused")
+public class CorsFilter implements Filter {
+
+ public void destroy() {
+ }
+
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
+ throws IOException, ServletException {
+
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+ response.addHeader("Access-Control-Allow-Origin", "*");
+ response.addHeader("Access-Control-Allow-Methods", "*");
+ response.addHeader("Access-Control-Allow-Headers",
+ "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range");
+
+ if (request.getMethod().equals(HttpMethod.OPTIONS.toString())) {
+ response.addHeader("Access-Control-Max-Age", "1728000");
+ response.setStatus(HttpServletResponse.SC_ACCEPTED);
+ return;
+ }
+ chain.doFilter(request, servletResponse);
+ }
+
+ public void init(FilterConfig fConfig) throws ServletException {
+ }
+
+} \ No newline at end of file