diff options
author | Serban Jora <jora@research.att.com> | 2017-08-29 15:52:57 -0400 |
---|---|---|
committer | Serban Jora <jora@research.att.com> | 2017-09-01 00:07:55 -0400 |
commit | 5699eb248346eb6dd59f42605aeb56af41b15cab (patch) | |
tree | 81bf4a4ce2d05022612cd00254fdfd37a765be43 /javatoscachecker/service/src/main/java/org | |
parent | db87c4f77a730e571338c2bf7bfcc9fdc5272185 (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')
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; + } + } +} |