summaryrefslogtreecommitdiffstats
path: root/javatoscachecker/service/src/main/java/org
diff options
context:
space:
mode:
authorSerban Jora <jora@research.att.com>2017-08-29 15:52:57 -0400
committerSerban Jora <jora@research.att.com>2017-09-01 00:07:55 -0400
commit5699eb248346eb6dd59f42605aeb56af41b15cab (patch)
tree81bf4a4ce2d05022612cd00254fdfd37a765be43 /javatoscachecker/service/src/main/java/org
parentdb87c4f77a730e571338c2bf7bfcc9fdc5272185 (diff)
Add initial ATT tosca checker tool
Addressed license headers and copyright owner issues Addressed project folder name Issue-ID: MODELING-7 Change-Id: I150784c5871bb6093ff0a6615639088bc2e0c496 Signed-off-by: Serban Jora <jora@research.att.com>
Diffstat (limited to 'javatoscachecker/service/src/main/java/org')
-rw-r--r--javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CachedTarget.java99
-rw-r--r--javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/Catalogs.java117
-rw-r--r--javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CheckerController.java260
-rw-r--r--javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CheckerEngine.java89
-rw-r--r--javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/NoSuchCatalogException.java24
-rw-r--r--javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/TargetConflictException.java24
-rw-r--r--javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/TemplateChecker.java121
7 files changed, 734 insertions, 0 deletions
diff --git a/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CachedTarget.java b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CachedTarget.java
new file mode 100644
index 0000000..943891f
--- /dev/null
+++ b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CachedTarget.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017 <AT&T>. All rights reserved.
+ * ===================================================================
+ * 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.tosca.checker.service;
+
+import java.io.FilterReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.IOException;
+
+import java.net.URI;
+
+import org.springframework.core.io.Resource;
+
+import org.apache.commons.io.input.CharSequenceReader;
+
+import org.onap.tosca.checker.Target;
+
+
+/**
+ * Cache of the target content until invalidation ..
+ */
+public class CachedTarget extends Target {
+
+ private StringBuilder content;
+
+ public CachedTarget(String theName, URI theResource) {
+ super(theName, theResource);
+ }
+
+ public CachedTarget(Resource theResource) throws IOException {
+ super(theResource.getFilename(), theResource.getURI());
+ }
+
+ protected CachedTarget(CachedTarget theSource) {
+ super(theSource.getName(), theSource.getLocation());
+ if (theSource.hasContent()) {
+ setContent(theSource.getContent());
+ }
+ }
+
+ protected boolean hasContent() {
+ return this.content != null;
+ }
+
+ protected CharSequence getContent() {
+ return this.content == null ? null : this.content;
+ }
+
+ protected void setContent(CharSequence theContent) {
+ this.content = new StringBuilder(theContent);
+ }
+
+ /*
+ */
+ public void invalidate() {
+ this.content = null;
+ setTarget(null);
+ }
+
+ @Override
+ public Reader open() throws IOException {
+ return this.content != null ?
+ new CharSequenceReader(this.content) :
+ new FilterReader(super.open()) {
+ {
+ content = new StringBuilder();
+ }
+
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ int res = super.read(cbuf, off, len);
+ if (res > 0)
+ content.append(cbuf, off, res);
+ return res;
+ }
+
+ public int read() throws IOException {
+ int res = super.read();
+ if (res > 0)
+ /* the cast here is troublesome: the original stream had an encoding and this cast has to
+ done with respect to that. */
+ content.append((char)res);
+ return res;
+ }
+
+ };
+ }
+
+}
+
diff --git a/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/Catalogs.java b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/Catalogs.java
new file mode 100644
index 0000000..e792286
--- /dev/null
+++ b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/Catalogs.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017 <AT&T>. All rights reserved.
+ * ===================================================================
+ * 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.tosca.checker.service;
+
+import java.net.URI;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Collection;
+import java.util.Collections;
+
+import java.util.stream.Collectors;
+
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.onap.tosca.checker.Checker;
+import org.onap.tosca.checker.Catalog;
+import org.onap.tosca.checker.Target;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.FatalBeanException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+
+import org.springframework.stereotype.Component;
+import org.springframework.context.annotation.Scope;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Component("catalogs")
+@Scope("singleton")
+@ConfigurationProperties(prefix="catalogs")
+public class Catalogs implements ApplicationContextAware {
+
+ private static Logger logger = Logger.getLogger(Catalogs.class.getName());
+
+ private ApplicationContext appCtx;
+ private ResourcePatternResolver resolver;
+ private Map<String, Catalog> catalogs = new HashMap<String, Catalog>();
+
+ public Catalogs() {
+ resolver = new PathMatchingResourcePatternResolver();
+ }
+
+ public void setApplicationContext(ApplicationContext theCtx) throws BeansException {
+ this.appCtx = theCtx;
+ }
+
+ @PostConstruct
+ public void initCatalogs() {
+ logger.entering(getClass().getName(), "initCatalogs");
+
+ // Done
+ logger.log(Level.INFO, "Catalogs available");
+ }
+
+ @PreDestroy
+ public void cleanupCatalogs() {
+ logger.entering(getClass().getName(), "destroyCatalogs");
+ }
+
+ public Catalog getCatalog(String theName) {
+
+System.out.println("getCatalog: " + theName + ". Known catalogs: " + this.catalogs.keySet());
+
+ return this.catalogs.get(theName);
+ }
+
+ public void setCatalog(String theName, Catalog theCatalog) {
+ this.catalogs.put(theName, theCatalog);
+ }
+
+ public Catalog removeCatalog(String theName) {
+ return this.catalogs.remove(theName);
+ }
+
+ /* configuration interface */
+ public void setCatalogs(Map<String, ?> theCatalogs) {
+ //just look here at the pain of creating a checker ever time ..
+ for (Map.Entry<String, ?> catalogEntry: theCatalogs.entrySet()) {
+ try {
+ Checker checker = new Checker();
+ checker.check((String)catalogEntry.getValue());
+ setCatalog(catalogEntry.getKey(), checker.catalog());
+ }
+ catch (Exception x) {
+ throw new FatalBeanException("Failed to add catalog " + catalogEntry.getKey() + " from " + catalogEntry.getValue(), x);
+ }
+ }
+ }
+
+ public Map<String, ?> getCatalogs() {
+ return this.catalogs;
+ }
+
+}
diff --git a/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CheckerController.java b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CheckerController.java
new file mode 100644
index 0000000..cde0323
--- /dev/null
+++ b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CheckerController.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2017 <AT&T>. All rights reserved.
+ * ===================================================================
+ * 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.tosca.checker.service;
+
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+import java.util.concurrent.Callable;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanInitializationException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.onap.tosca.checker.Checker;
+import org.onap.tosca.checker.CheckerException;
+import org.onap.tosca.checker.Report;
+import org.onap.tosca.checker.Catalog;
+import org.onap.tosca.checker.Target;
+import org.onap.tosca.checker.TargetLocator;
+import org.onap.tosca.checker.CommonLocator;
+
+
+
+@RestController
+public class CheckerController implements ApplicationContextAware {
+
+ private static Logger log = Logger.getLogger(CheckerController.class.getName());
+
+ private ApplicationContext appCtx;
+ @Autowired
+ private Catalogs catalogs;
+ private Checker checker;
+
+ public void setApplicationContext(ApplicationContext theCtx) throws BeansException {
+ this.appCtx = theCtx;
+ }
+
+ /**
+ * standalone checking, everything will be forgotten
+ */
+ @RequestMapping(value={"/check_template/"}, method={RequestMethod.POST}, produces={"application/json"})
+ public Report validate(@RequestBody String theTemplate,
+ HttpServletRequest theRequest) {
+
+System.out.println("Posting unnamed template");
+ CachedTarget target = new CachedTarget("", requestURI(theRequest));
+ target.setContent(theTemplate);
+ ((InCatalogLocator)this.checker.getTargetLocator()).setCatalog(null);
+
+ try {
+ this.checker.check(target);
+ }
+ catch (CheckerException cx) {
+ log.log(Level.WARNING, "Failed to check tosca template", cx);
+ target.getReport().add(cx);
+ }
+
+ return target.getReport();
+ }
+
+ /**
+ * checking with respect to a namespace/catalog but the outcome is forgotten (not added to the catalog)
+ */
+ @RequestMapping(value={"/check_template/{catalog}"}, method={RequestMethod.POST}, produces={"application/json"})
+ public Report validate(@RequestBody String theTemplate,
+ @PathVariable(value="catalog") String theCatalog,
+ HttpServletRequest theRequest)
+ throws NoSuchCatalogException {
+
+System.out.println("Posting unnamed template to catalog " + theCatalog);
+ Catalog catalog = this.catalogs.getCatalog(theCatalog);
+ if (catalog == null)
+ throw new NoSuchCatalogException(theCatalog);
+ else
+ ((InCatalogLocator)this.checker.getTargetLocator()).setCatalog(catalog);
+
+ CachedTarget target = new CachedTarget("", requestURI(theRequest));
+ target.setContent(theTemplate);
+
+ try {
+ this.checker.check(target, new Catalog(catalog));
+ }
+ catch (CheckerException cx) {
+ log.log(Level.WARNING, "Failed to check tosca template", cx);
+ target.getReport().add(cx);
+ }
+
+ return target.getReport();
+ }
+
+ /**
+ * checking with respect to a namespace/catalog, the outcome is registered within the catalog
+ */
+ @RequestMapping(value={"/check_template/{catalog}/{name}"}, method={RequestMethod.POST}, produces={"application/json"})
+ public Report validate(@RequestBody String theTemplate,
+ @PathVariable(value="catalog") String theCatalog,
+ @PathVariable(value="name") String theName,
+ HttpServletRequest theRequest)
+ throws TargetConflictException {
+System.out.println("Posting template named " + theName + " to catalog " + theCatalog);
+
+ Catalog catalog = this.catalogs.getCatalog(theCatalog);
+ ((InCatalogLocator)this.checker.getTargetLocator()).setCatalog(catalog);
+
+ URI targetURI = requestURI(theRequest);
+ if (catalog != null) {
+ if (catalog.getTarget(targetURI) != null)
+ throw new TargetConflictException(theName, theCatalog);
+ }
+
+ CachedTarget target = new CachedTarget("", targetURI);
+ target.setContent(theTemplate);
+
+ try {
+ if (catalog == null)
+ this.checker.check(target);
+ else
+ this.checker.check(target, catalog);
+ }
+ catch (CheckerException cx) {
+ log.log(Level.WARNING, "Failed to check tosca template", cx);
+ target.getReport().add(cx);
+ }
+
+ if (target.getReport().isEmpty() && catalog == null)
+ this.catalogs.setCatalog(theCatalog, checker.catalog());
+
+ return target.getReport();
+ }
+
+ @RequestMapping(value={"/check_template/{catalog}"}, method={RequestMethod.GET})
+ public ResponseEntity<Void> validate(@PathVariable(value="catalog") String theCatalog) {
+
+ Catalog cat = catalogs.getCatalog(theCatalog);
+ if (cat == null) {
+ return new ResponseEntity(HttpStatus.NOT_FOUND);
+ }
+
+ return new ResponseEntity(HttpStatus.OK);
+ }
+
+ @RequestMapping(value={"/check_template/{catalog}"}, method={RequestMethod.DELETE})
+ public ResponseEntity<Void> deleteCatalog(@PathVariable(value="catalog") String theCatalog) {
+
+ Catalog cat = catalogs.removeCatalog(theCatalog);
+ if (cat == null) {
+ return new ResponseEntity(HttpStatus.NOT_FOUND);
+ }
+
+ return new ResponseEntity(HttpStatus.OK);
+ }
+
+ @RequestMapping(value={"/check_template/{catalog}/{name}"}, method={RequestMethod.GET})
+ public ResponseEntity<String> retrieve(@PathVariable(value="catalog") String theCatalog,
+ @PathVariable(value="name") String theTemplateName,
+ HttpServletRequest theRequest) {
+
+ Catalog cat = catalogs.getCatalog(theCatalog);
+ if (cat == null) {
+ return new ResponseEntity(HttpStatus.NOT_FOUND);
+ }
+
+ Target t = cat.getTarget(requestURI(theRequest));
+ if (t == null) {
+ return new ResponseEntity(HttpStatus.NOT_FOUND);
+ }
+
+ return new ResponseEntity("{}", HttpStatus.OK);
+ }
+
+
+ @PostConstruct
+ public void initController() {
+ log.entering(getClass().getName(), "initCheckerController");
+
+ try {
+ this.checker = new Checker();
+ this.checker.setTargetLocator(new InCatalogLocator());
+ }
+ catch (CheckerException cx) {
+ log.log(Level.WARNING, "CheckerController setup failed", cx);
+ throw new BeanInitializationException("Failed to create a checker", cx);
+ }
+
+ log.log(Level.INFO, "CheckerController started");
+ }
+
+ @PreDestroy
+ public void cleanupController() {
+ log.entering(getClass().getName(), "cleanupCheckerController");
+ }
+
+ private URI requestURI(HttpServletRequest theRequest) {
+ try {
+ return new URI(String.format("%s://%s:%d%s", theRequest.getScheme(),
+ theRequest.getServerName(),
+ theRequest.getServerPort(),
+ theRequest.getRequestURI().toString()));
+ }
+ catch(URISyntaxException urisx) {
+ throw new RuntimeException(urisx);
+ }
+ }
+
+ /**
+ */
+ public static class InCatalogLocator extends CommonLocator {
+
+ private ThreadLocal<Catalog> catalog = new ThreadLocal();
+
+ public InCatalogLocator() {
+ }
+
+ protected void setCatalog(Catalog theCatalog) {
+ this.catalog.set(theCatalog);
+ }
+
+ /** */
+ @Override
+ public Target resolve(String theName) {
+ Target target = null;
+ if (this.catalog.get() != null)
+ target = this.catalog.get()
+ .targets()
+ .stream()
+ .filter(t -> t.getName().equals(theName))
+ .findFirst()
+ .orElse(null);
+ return target == null ? super.resolve(theName) : target;
+ }
+ }
+
+}
diff --git a/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CheckerEngine.java b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CheckerEngine.java
new file mode 100644
index 0000000..24c168b
--- /dev/null
+++ b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/CheckerEngine.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 <AT&T>. All rights reserved.
+ * ===================================================================
+ * 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.tosca.checker.service;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ImportResource;
+//import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+
+/**
+ * This is the entry point of the validation engine.
+ * The maven build script packages the application as a 'all-in-one' jar. As such, there are 2 ways to start
+ * the application:
+ * java -jar ASC-Validator-some_version.jar
+ * or
+ * java -cp some_path/ASC-Validator-some_version.jar org.springframework.boot.loader.JarLauncher
+ *
+ * The second version is important because it gets around the known java issue/bug of not being able to specify
+ * additional classpath elements when using the '-jar' option (additional '-cp' options are being ignored). This
+ * version allows to add to the classpath the location of additional configuration.
+ *
+ * The approach in packaging the application was to include in the (all-in-one) package the known configurations
+ * (such that it is as easy as possible to install/setup/start the applications) while still having the possibility
+ * of re-specifying (some of) the configuration.
+ *
+ * All out beans are specified within 'checker.xml'; use spring profiles to distinguish between the
+ * configurations for each environment.
+ * <beans profile="dev"> .. </beans>
+ * <beans profile="ist"> .. </beans>
+ *
+ * The default configuration is for the development environment. In order to run a particular configuration we use the
+ * spring.profiles.active environment variable, as in:
+ * java -Dspring.profiles.active=ist -jar some_path/ASC-Validator-Service-some_version.jar
+ * or
+ * java -Dspring.profiles.active=ist -cp some_path/ASC-Validator-some_version.jar org.springframework.boot.loader.JarLauncher
+ *
+ * Note: we can have a 'common' profile to be always activated that includes those bean specifications least likely to
+ * change.
+ *
+ * Resource reference syntax:
+ * classpath*:validator.xml
+ * vs
+ * classpath:validator.xml
+ *
+ * In the first case we direct the bean loader to find *ALL* validator.xml files in the classpath and merge them
+ * (merge the parts for the active profile(s))
+ * In the second case we instruct the bean loader to locate the *FIRST* validator.xml file and process it. All others
+ * (validator.xml) files will be ignored.
+ *
+ * Overwriting pre-packaged bean configuration:
+ * The first version would theoretically allow us to specify beans configuration deltas (with respect to the
+ * pre-packaged version). In practice I did not manage to have this approach working reliably: it relies on a
+ * deterministic order of classpath processing and on overriding some of the spring framework defaults (in not so
+ * obvious ways, bean indexing for example).
+ * Currently we enable the second option, i.e. one has to provide a FULL alternative bean configuration. This
+ * alternative configuration can be specified as overwriting an existing profile or as an entirely new profile.
+ * (when using alternative profiles the resourcec reference syntax is irrelevant ..)
+ */
+
+@SpringBootApplication(scanBasePackages={"org.onap.tosca.checker.service"})
+@ImportResource({"classpath:${beans.config?:checker}.xml"})
+@EnableScheduling
+public class CheckerEngine
+{
+
+ public CheckerEngine() {
+ }
+
+ public static void main(String theArgs[]) {
+ SpringApplication sapp = new SpringApplication(CheckerEngine.class);
+ ConfigurableApplicationContext ctx = sapp.run(theArgs);
+ }
+
+}
diff --git a/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/NoSuchCatalogException.java b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/NoSuchCatalogException.java
new file mode 100644
index 0000000..5f0d29d
--- /dev/null
+++ b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/NoSuchCatalogException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017 <AT&T>. All rights reserved.
+ * ===================================================================
+ * 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.tosca.checker.service;
+
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.http.HttpStatus;
+
+@ResponseStatus(value=HttpStatus.PRECONDITION_FAILED, reason="No such catalog exists in the service")
+public class NoSuchCatalogException extends Exception {
+
+ public NoSuchCatalogException(String theCatalog) {
+ super("This service instance has not catalog with the name " + theCatalog);
+ }
+}
diff --git a/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/TargetConflictException.java b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/TargetConflictException.java
new file mode 100644
index 0000000..928412f
--- /dev/null
+++ b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/TargetConflictException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017 <AT&T>. All rights reserved.
+ * ===================================================================
+ * 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.tosca.checker.service;
+
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.http.HttpStatus;
+
+@ResponseStatus(value=HttpStatus.PRECONDITION_FAILED, reason="Same target exists in given catalog")
+public class TargetConflictException extends Exception {
+
+ public TargetConflictException(String theTarget, String theCatalog) {
+ super("A target with name " + theTarget + " already exists in " + theCatalog);
+ }
+}
diff --git a/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/TemplateChecker.java b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/TemplateChecker.java
new file mode 100644
index 0000000..6227236
--- /dev/null
+++ b/javatoscachecker/service/src/main/java/org/onap/tosca/checker/service/TemplateChecker.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017 <AT&T>. All rights reserved.
+ * ===================================================================
+ * 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.tosca.checker.service;
+
+import java.net.URI;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Collections;
+import java.util.logging.Logger;
+import java.util.logging.Level;
+import java.util.concurrent.Callable;
+
+import org.onap.tosca.checker.Target;
+import org.onap.tosca.checker.CommonLocator;
+import org.onap.tosca.checker.Checker;
+import org.onap.tosca.checker.Catalog;
+import org.onap.tosca.checker.Report;
+import org.onap.tosca.checker.CheckerException;
+
+import org.springframework.stereotype.Component;
+import org.springframework.context.annotation.Scope;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ */
+@Component("templateChecker")
+@Scope("prototype")
+public class TemplateChecker implements Callable<Report> {
+
+ private static Logger log = Logger.getLogger(TemplateChecker.class.getName());
+
+ private String template,
+ name,
+ catalog;
+ private URI uri;
+
+ @Autowired
+ private Catalogs catalogs;
+
+ /* */
+ public TemplateChecker(String theTemplate, String theName, String theCatalog, URI theRef) {
+ this.template = theTemplate;
+ this.name = theName;
+ this.catalog = theCatalog;
+ this.uri = theRef;
+ }
+
+ /*
+ */
+ @Override
+ public Report call() throws Exception {
+
+ if (log.isLoggable(Level.FINEST))
+ log.log(Level.FINEST, "Processing template " + this.template);
+
+ Catalog cat = catalogs.getCatalog(this.catalog);
+
+ log.log(Level.FINER, "validating template " + this.name + " at " + this.uri + ". Active catalog: " + cat);
+
+ //because this is a new checker we do not care about the top target name ..
+ CachedTarget target = new CachedTarget(this.name == null ? "" : this.name, this.uri);
+ target.setContent(this.template);
+ Checker checker = new Checker();
+ checker.setTargetLocator(new InCatalogLocator(cat));
+ try {
+ if (cat != null) {
+ checker.check(target, cat);
+ }
+ else {
+ checker.check(target);
+ }
+ }
+ catch (CheckerException cx) {
+ log.log(Level.WARNING, "Failed to check tosca template", cx);
+ target.getReport().add(cx);
+ }
+
+ //if named template is succesfull and this is a new catalog, register it
+ if (this.name != null && target.getReport().isEmpty() && cat == null) {
+ this.catalogs.setCatalog(this.catalog, checker.catalog());
+ }
+
+ return target.getReport().isEmpty() ? null : target.getReport();
+
+ }
+
+
+ public static class InCatalogLocator extends CommonLocator {
+
+ private Catalog catalog;
+
+ public InCatalogLocator(Catalog theCatalog) {
+ this.catalog = theCatalog;
+ }
+
+ /** */
+ @Override
+ public Target resolve(String theName) {
+ Target target = null;
+ if (this.catalog != null)
+ target = this.catalog.targets()
+ .stream()
+ .filter(t -> t.getName().equals(theName))
+ .findFirst()
+ .orElse(null);
+ return target == null ? super.resolve(theName) : target;
+ }
+ }
+}