From 5032434b101f25fa44d2e1f8dc8393e30af1ed4f Mon Sep 17 00:00:00 2001 From: "Stone, Avi (as206k)" Date: Thu, 12 Apr 2018 15:46:31 +0300 Subject: DCAE-D be initial commit DCAE-D be initial commit Issue-ID: SDC-1218 Change-Id: Id18ba96c499e785aa9ac395fbaf32d57f08c281b Signed-off-by: Stone, Avi (as206k) --- dcaedt_catalog/commons/pom.xml | 135 +++++++++ .../org/onap/sdc/dcae/catalog/commons/Action.java | 11 + .../org/onap/sdc/dcae/catalog/commons/Actions.java | 201 +++++++++++++ .../org/onap/sdc/dcae/catalog/commons/Future.java | 35 +++ .../sdc/dcae/catalog/commons/FutureHandler.java | 13 + .../org/onap/sdc/dcae/catalog/commons/Futures.java | 257 ++++++++++++++++ .../org/onap/sdc/dcae/catalog/commons/Http.java | 107 +++++++ .../catalog/commons/JSONHttpMessageConverter.java | 100 +++++++ .../onap/sdc/dcae/catalog/commons/ListBuilder.java | 59 ++++ .../onap/sdc/dcae/catalog/commons/MapBuilder.java | 80 +++++ .../org/onap/sdc/dcae/catalog/commons/Neo.java | 54 ++++ .../org/onap/sdc/dcae/catalog/commons/Proxies.java | 37 +++ .../org/onap/sdc/dcae/catalog/commons/Proxy.java | 144 +++++++++ .../org/onap/sdc/dcae/catalog/commons/Proxy.pojo | 145 +++++++++ .../sdc/dcae/catalog/commons/ProxyBuilder.java | 92 ++++++ .../onap/sdc/dcae/catalog/commons/Recycler.java | 329 +++++++++++++++++++++ 16 files changed, 1799 insertions(+) create mode 100644 dcaedt_catalog/commons/pom.xml create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Action.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Actions.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Future.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/FutureHandler.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Futures.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Http.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/JSONHttpMessageConverter.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/ListBuilder.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/MapBuilder.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Neo.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxies.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxy.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxy.pojo create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/ProxyBuilder.java create mode 100644 dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Recycler.java (limited to 'dcaedt_catalog/commons') diff --git a/dcaedt_catalog/commons/pom.xml b/dcaedt_catalog/commons/pom.xml new file mode 100644 index 0000000..d285e1b --- /dev/null +++ b/dcaedt_catalog/commons/pom.xml @@ -0,0 +1,135 @@ + + 4.0.0 + + org.onap.sdc.dcae + DCAE-DT-Catalog + 1806.0.1-SNAPSHOT + + DCAE-DT-Catalog-Commons + jar + DCAE DT Catalog Commons + + + src/main/java + + + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/deps + false + false + true + + + + + + org.codehaus.mojo + buildnumber-maven-plugin + 1.4 + + + validate + + create + + + + + false + false + + + + org.apache.maven.plugins + maven-jar-plugin + 2.1 + + + + true + + + ${buildNumber} + + + + + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + + + commons-io + commons-io + 2.4 + + + commons-cli + commons-cli + 1.3 + + + commons-beanutils + commons-beanutils + 1.9.3 + + + commons-jxpath + commons-jxpath + 1.3 + + + com.google.guava + guava + 17.0 + + + org.yaml + snakeyaml + 1.17 + + + org.json + json + 20160212 + + + com.fasterxml.jackson.core + jackson-databind + 2.7.8 + + + com.github.wnameless + json-flattener + 0.2.2 + + + org.springframework + spring-web + 4.3.5.RELEASE + + + diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Action.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Action.java new file mode 100644 index 0000000..fb36950 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Action.java @@ -0,0 +1,11 @@ +package org.onap.sdc.dcae.catalog.commons; + +import org.onap.sdc.dcae.catalog.commons.Future; + +/** + */ +public interface Action { + + public Future execute(); + +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Actions.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Actions.java new file mode 100644 index 0000000..132b0c0 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Actions.java @@ -0,0 +1,201 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.List; +import java.util.LinkedList; +import java.util.ArrayList; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.catalog.commons.Action; +import org.onap.sdc.dcae.catalog.commons.Future; +import org.onap.sdc.dcae.catalog.commons.FutureHandler; +import org.onap.sdc.dcae.catalog.commons.Futures; + +/** + */ +public interface Actions { + + /** */ + public static interface CompoundAction extends Action> { + + public CompoundAction addAction(Action theAction); + + public List> actions(); + + public Future> execute(); + } + + + public static class BasicCompoundAction implements CompoundAction { + + private LinkedList> actions = new LinkedList>(); + + + + public CompoundAction addAction(Action theAction) { + this.actions.add(theAction); + return this; + } + + public List> actions() { + return this.actions; + } + + public Future> execute() { + CompoundFuture cf = new CompoundFuture(this.actions.size()); + for (Action a: this.actions) + cf.addFuture(a.execute()); + return cf; + } + } + + + public static class CompoundFuture extends Futures.BasicFuture> { + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + private LinkedList> futures = new LinkedList>(); + private FutureHandler hnd; + + CompoundFuture(int theActionCount) { + + hnd = new Futures.BasicHandler(new CountDownLatch(theActionCount)) { + + private List results = new ArrayList(Collections.nCopies(theActionCount, null)); + + protected void process(Future theResult) { + synchronized(CompoundFuture.this) { + if (theResult.failed()) { + CompoundFuture.this.cause(theResult.cause()); + //and stop processing of other results + this.results = null; + //?? + } + else { + if (this.results != null) + this.results.set(futures.indexOf(theResult), theResult.result()); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Got result for action {}. Count at {}", futures.indexOf(theResult), this.latch.getCount()); + } + if (this.latch.getCount() == 1) {//this was the last result + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Got all results: {}", this.results); + CompoundFuture.this.result(this.results); + } + } + } + }; + } + + CompoundFuture addFuture(Future theFuture) { + synchronized(this) { + futures.add(theFuture); + theFuture.setHandler(this.hnd); + } + return this; + } + + } + +/* + public static class CompoundFutureHandler implements FutureHandler { + + protected List result = null; + protected List error = null; + protected CountDownLatch latch = null; + + CompoundFutureHandler(int theResultCount) { + this(new CountDownLatch(theResultCount)); + } + + public void handle(Future theResult) { + if (this.latch != null) { + this.latch.countDown(); + } + } + + public T result() + throws InterruptedException, RuntimeException { + return result(true); + } + + public BasicHandler waitForCompletion() throws InterruptedException { + this.latch.await(); + return this; + } + + } +*/ + + public static class Sequence implements Action> { + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + private List> actions = new LinkedList>(); + private int current = 0; + private SequenceFuture future = new SequenceFuture(); + + public Sequence add(Action theAction) { + if (this.current > 0) + throw new IllegalStateException("In execution"); + this.actions.add(theAction); + return this; + } + + /* we allow 'early' access to the future so that a client can pass its reference while + * it still builds the sequence, for example. + */ + public Future> future() { + return this.future; + } + + //need to add protection when for the 'no action' case + public Future> execute() { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Starting serialized execution of {}", actions); + if (hasNext()) + next().execute().setHandler(future.hnd); + return this.future; + } + + protected boolean hasNext() { + return this.current < actions.size(); + } + + protected Action next() { + return actions.get(this.current++); + } + + private class SequenceFuture extends Futures.BasicFuture> { + + private List results = new LinkedList(); + private FutureHandler hnd = new Futures.BasicHandler() { + + protected void process(Future theResult) { + + if (theResult.failed()) { + SequenceFuture.this.cause(theResult.cause()); + //and stop processing of other results + } + else { + SequenceFuture.this.results.add(theResult.result()); + if (Sequence.this.hasNext()) { + Sequence.this.next().execute().setHandler(this); + } + else { + SequenceFuture.this.result(SequenceFuture.this.results); + } + } + } + }; + + + } + + + + } + +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Future.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Future.java new file mode 100644 index 0000000..c50f467 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Future.java @@ -0,0 +1,35 @@ +package org.onap.sdc.dcae.catalog.commons; + +import org.onap.sdc.dcae.catalog.commons.Future; +import org.onap.sdc.dcae.catalog.commons.FutureHandler; + +/** + * Modeled after the vertx future + */ +public interface Future { + + public T result(); + + public Future result(T theResult); + +//rename 'cause' to 'failure' + + public Throwable cause(); + + public Future cause(Throwable theError); + + public boolean succeeded(); + + public boolean failed(); + + public boolean complete(); + + public T waitForResult() throws Exception; + + //public T waitForResult(long theTimeout) throws Exception; + + public Future waitForCompletion() throws InterruptedException; + + public Future setHandler(FutureHandler theHandler); + +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/FutureHandler.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/FutureHandler.java new file mode 100644 index 0000000..b689412 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/FutureHandler.java @@ -0,0 +1,13 @@ +package org.onap.sdc.dcae.catalog.commons; + +import org.onap.sdc.dcae.catalog.commons.Future; + +/** + * Modeled after the vertx future + */ +@FunctionalInterface +public interface FutureHandler { + + public void handle(Future theResult); + +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Futures.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Futures.java new file mode 100644 index 0000000..ffaf42b --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Futures.java @@ -0,0 +1,257 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.List; +import java.util.LinkedList; +import java.util.Collections; + +import java.util.concurrent.CountDownLatch; +import java.util.function.Function; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.dcae.catalog.commons.Future; +import org.onap.sdc.dcae.catalog.commons.FutureHandler; +import org.onap.sdc.common.onaplog.Enums.LogLevel; + + +/** + */ +public class Futures { + + private Futures() { + } + + + public static Future failedFuture(Throwable theError) { + return new BasicFuture() + .cause(theError); + } + + public static Future succeededFuture(T theResult) { + return new BasicFuture() + .result(theResult); + } + + public static Future future() { + return new BasicFuture(); + } + + public static Future advance(Future theStep, + final Function theResultFunction) { + return advance(theStep, theResultFunction, Function.identity()); + } + + public static Future advance(Future theStep, + final Function theResultFunction, + final Function theErrorFunction) { + final Future adv = new BasicFuture(); + theStep.setHandler(new FutureHandler() { + public void handle(Future theResult) { + if (theResult.failed()) + adv.cause(theErrorFunction.apply(theResult.cause())); + else + adv.result(theResultFunction.apply(theResult.result())); + } + }); + return adv; + } + + /** */ + public static class BasicFuture implements Future { + + protected boolean succeeded, + failed; + + protected FutureHandler handler; + protected Throwable cause; + protected T result; + + + protected BasicFuture() { + } + + public T result() { + return this.result; + } + + public Future result(T theResult) { + this.result = theResult; + this.succeeded = true; + this.cause = null; + this.failed = false; + callHandler(); + return this; + } + + public Throwable cause() { + return this.cause; + } + + public Future cause(Throwable theCause) { + this.cause = theCause; + this.failed = true; + this.result = null; + this.succeeded = false; + callHandler(); + return this; + } + + public boolean succeeded() { + return this.succeeded; + } + + public boolean failed() { + return this.failed; + } + + public boolean complete() { + return this.failed || this.succeeded; + } + + public Future setHandler(FutureHandler theHandler) { + this.handler = theHandler; + callHandler(); + return this; + } + + public T waitForResult() throws Exception { + BasicHandler hnd = buildHandler(); + setHandler(hnd); + hnd.waitForCompletion(); + if (failed()) + throw (Exception)cause(); + else + return result(); + } + + public Future waitForCompletion() throws InterruptedException { + BasicHandler hnd = buildHandler(); + setHandler(hnd); + hnd.waitForCompletion(); + return this; + } + + protected void callHandler() { + if (this.handler != null && complete()) { + this.handler.handle(this); + } + } + + protected BasicHandler buildHandler() { + return new BasicHandler(); + } + } + + + /** */ + public static class BasicHandler + implements FutureHandler { + + protected T result = null; + protected Throwable error = null; + protected CountDownLatch latch = null; + + BasicHandler() { + this(new CountDownLatch(1)); + } + + BasicHandler(CountDownLatch theLatch) { + this.latch = theLatch; + } + + public void handle(Future theResult) { + process(theResult); + if (this.latch != null) { + this.latch.countDown(); + } + } + + protected void process(Future theResult) { + if (theResult.failed()) { + this.error = theResult.cause(); + } + else { + this.result = theResult.result(); + } + } + + public T result(boolean doWait) + throws InterruptedException, RuntimeException { + if (doWait) { + waitForCompletion(); + } + if (null == this.error) + return this.result; + + throw new RuntimeException(this.error); + } + + public T result() + throws InterruptedException, RuntimeException { + return result(true); + } + + public BasicHandler waitForCompletion() throws InterruptedException { + this.latch.await(); + return this; + } + } + + /** */ + public static class Accumulator extends BasicFuture> + implements Future> { + + protected List> futures = new LinkedList>(); + //protected List results = new LinkedList(); + protected BasicHandler handler = null; + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + public Accumulator() { + this.result = new LinkedList(); + } + + public Accumulator add(Future theFuture) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Intersection add"); + this.futures.add(theFuture); + this.result.add(null); + return this; + } + + public Accumulator addAll(Accumulator theFutures) { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Intersection addAll"); + + return this; + } + + public Future> accumulate() { + this.futures = Collections.unmodifiableList(this.futures); + this.handler = new BasicHandler(new CountDownLatch(this.futures.size())) { + protected void process(Future theResult) { + if (theResult.failed()) { + Accumulator.this.cause = theResult.cause(); + } + else { + Accumulator.this.result.set( + Accumulator.this.futures.indexOf(theResult), theResult.result()); + } + if (this.latch.getCount() == 1) { + if (Accumulator.this.cause != null) + Accumulator.this.cause(Accumulator.this.cause); + else + Accumulator.this.result(Accumulator.this.result); + } + } + }; + futures.stream() + .forEach(f -> f.setHandler(this.handler)); + + return this; + } + + } + + +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Http.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Http.java new file mode 100644 index 0000000..0f28495 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Http.java @@ -0,0 +1,107 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.List; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.util.concurrent.ListenableFutureCallback; +import org.springframework.web.client.AsyncRestTemplate; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +public class Http { + + protected Http() { + } + + + public static Future exchange(String theUri, HttpMethod theMethod, HttpEntity theRequest, Class theResponseType) { + + AsyncRestTemplate restTemplate = new AsyncRestTemplate(); + + List> converters = restTemplate.getMessageConverters(); + converters.add(0, new JSONHttpMessageConverter()); + restTemplate.setMessageConverters(converters); + + HttpFuture result = new HttpFuture(); + try { + restTemplate + .exchange(theUri, theMethod, theRequest, theResponseType) + .addCallback(result.callback); + } + catch (RestClientException rcx) { + return Futures.failedFuture(rcx); + } + catch (Exception x) { + return Futures.failedFuture(x); + } + + return result; + } + + /** + * + * @param theUri + * @param theMethod + * @param theRequest + * @param theResponseType + * @param readTimeOut pass -1 if you dont need to customize the read time out interval + * @return + */ + public static ResponseEntity exchangeSync(String theUri, HttpMethod theMethod, HttpEntity theRequest, Class theResponseType, int readTimeOut) { + + RestTemplate restTemplate = new RestTemplate(); + + if(readTimeOut!=-1){ + SimpleClientHttpRequestFactory rf = (SimpleClientHttpRequestFactory) restTemplate.getRequestFactory(); + rf.setReadTimeout(1 * readTimeOut); + } + + List> converters = restTemplate.getMessageConverters(); + converters.add(0, new JSONHttpMessageConverter()); + restTemplate.setMessageConverters(converters); + ResponseEntity result = null; + + try { + result = restTemplate.exchange(theUri, theMethod, theRequest, theResponseType); + } + catch (RestClientException rcx) { + return new ResponseEntity((T) rcx.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + catch (Exception x) { + return new ResponseEntity((T) x.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + + return result; + } + + + + public static class HttpFuture extends Futures.BasicFuture { + + HttpFuture() { + } + + ListenableFutureCallback> callback = new ListenableFutureCallback>() { + + public void onSuccess(ResponseEntity theResult) { + HttpFuture.this.result(theResult.getBody()); + } + + public void onFailure(Throwable theError) { + if (theError instanceof HttpClientErrorException) { + HttpFuture.this.cause(new Exception((HttpClientErrorException)theError)); + } + else { + HttpFuture.this.cause(theError); + } + } + }; + + } +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/JSONHttpMessageConverter.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/JSONHttpMessageConverter.java new file mode 100644 index 0000000..e711279 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/JSONHttpMessageConverter.java @@ -0,0 +1,100 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Type; +import java.nio.charset.Charset; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.AbstractHttpMessageConverter; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.converter.HttpMessageNotWritableException; + +import org.json.JSONObject; +import org.json.JSONArray; +import org.json.JSONTokener; +import org.json.JSONException; + +/** + */ +public class JSONHttpMessageConverter extends AbstractHttpMessageConverter { + + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + /** */ + public JSONHttpMessageConverter() { + super(new MediaType("application", "json", DEFAULT_CHARSET)); + } + /* + @Override + public boolean canRead(Class theClazz, MediaType theMediaType) { + return canRead(theMediaType); + } + + @Override + public boolean canWrite(Class theClazz, MediaType theMediaType) { + return canWrite(theMediaType); + } + */ + @Override + protected boolean supports(Class theClazz) { + return theClazz.equals(JSONObject.class) || + theClazz.equals(JSONArray.class); + } + + @Override + protected Object readInternal(Class theClazz, HttpInputMessage theInputMessage) + throws IOException, HttpMessageNotReadableException { + + Reader json = new InputStreamReader(theInputMessage.getBody(), getCharset(theInputMessage.getHeaders())); + + try { + if (theClazz.equals(JSONObject.class)) + return new JSONObject(new JSONTokener(json)); + if (theClazz.equals(JSONArray.class)) + return new JSONArray(new JSONTokener(json)); + + throw new HttpMessageNotReadableException("Could not process input, cannot handle " + theClazz); + } + catch (JSONException jsonx) { + throw new HttpMessageNotReadableException("Could not read JSON: " + jsonx.getMessage(), jsonx); + } + } + + @Override + protected void writeInternal(Object theObject, HttpOutputMessage theOutputMessage) + throws IOException, HttpMessageNotWritableException { + + Writer writer = new OutputStreamWriter(theOutputMessage.getBody(), getCharset(theOutputMessage.getHeaders())); + + try { + if (theObject instanceof JSONObject) { + ((JSONObject)theObject).write(writer); + } + else if (theObject instanceof JSONArray) { + ((JSONArray)theObject).write(writer); + } + + writer.close(); + } + catch(JSONException jsonx) { + throw new HttpMessageNotWritableException("Could not write JSON: " + jsonx.getMessage(), jsonx); + } + } + + private Charset getCharset(HttpHeaders theHeaders) { + if (theHeaders != null && + theHeaders.getContentType() != null && + theHeaders.getContentType().getCharSet() != null) { + return theHeaders.getContentType().getCharSet(); + } + return DEFAULT_CHARSET; + } + +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/ListBuilder.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/ListBuilder.java new file mode 100644 index 0000000..2538893 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/ListBuilder.java @@ -0,0 +1,59 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.Arrays; +import java.util.List; + +import org.onap.sdc.dcae.catalog.commons.ListBuilder; + +import java.util.LinkedList; + +public class ListBuilder { + + private List list; + + public ListBuilder() { + this.list = new LinkedList(); + } + + public boolean isEmpty() { + return this.list.isEmpty(); + } + + public ListBuilder add(T theValue) { + this.list.add(theValue); + return this; + } + + public ListBuilder addAll(final Iterable theValues) { + for (final T val : theValues) { + this.list.add(val); + } + return this; + } + + public ListBuilder addAll(final List theList) { + this.list.addAll(theList); + return this; + } + + public ListBuilder addAll(final T[] theArray) { + for (T t: theArray) this.list.add(t); + return this; + } + + public List build() { + return this.list; + } + + public List buildOpt() { + return this.list.isEmpty() ? null : this.list; + } + + public static List asList(V[] theArray) { + return Arrays.asList(theArray); + } + + public static List asListOpt(V[] theArray) { + return (theArray != null && theArray.length > 0) ? Arrays.asList(theArray) : null; + } +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/MapBuilder.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/MapBuilder.java new file mode 100644 index 0000000..3aa2a56 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/MapBuilder.java @@ -0,0 +1,80 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.Map; +import java.util.HashMap; +import java.util.function.Function; + +import org.onap.sdc.dcae.catalog.commons.MapBuilder; + +import java.util.function.BiFunction; + +public class MapBuilder { + + private Map map; + + public MapBuilder() { + this.map = new HashMap(); + } + + public boolean isEmpty() { + return this.map.isEmpty(); + } + + public MapBuilder put(K theKey, V theValue) { + this.map.put(theKey, theValue); + return this; + } + + public MapBuilder putOpt(K theKey, V theValue) { + if (theValue != null) { + this.map.put(theKey, theValue); + } + return this; + } + + public MapBuilder put(final Map.Entry theEntry) { + this.map.put(theEntry.getKey(), theEntry.getValue()); + return this; + } + + public MapBuilder putOpt(final Map.Entry theEntry) { + if (theEntry != null) { + this.map.put(theEntry.getKey(), theEntry.getValue()); + } + return this; + } + + public MapBuilder putAll(final Iterable> theEntries) { + for (final Map.Entry e : theEntries) { + this.map.put(e.getKey(), e.getValue()); + } + return this; + } + + /* If theEntries contains multiple entries with the same key then the key gets a suffix in order to make it unique + .. */ +// public MapBuilder forceAll(final Iterable> theEntries, + public MapBuilder forceAll(final Iterable> theEntries, + Function , K> rekeyFunction) { + for (final Map.Entry e : theEntries) { + K key = e.getKey(); + if (this.map.containsKey(key)) + key = rekeyFunction.apply((Map.Entry)e); + this.map.put(key, e.getValue()); + } + return this; + } + + public MapBuilder putAll(final Map theMap) { + this.map.putAll(theMap); + return this; + } + + public Map build() { + return this.map; + } + + public Map buildOpt() { + return this.map.isEmpty() ? null : this.map; + } +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Neo.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Neo.java new file mode 100644 index 0000000..f818163 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Neo.java @@ -0,0 +1,54 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.Iterator; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterators; + +import org.json.JSONObject; + + +public class Neo { + + /* + */ + public static String literalMap(JSONObject theProps, + String theNameAlias, + String theValueAlias, + String theAssignmentOp, + String theRelationOp, + Predicate theFieldFilter) { + if(theProps.length() == 0) + return ""; + StringBuilder sb = new StringBuilder(""); + for (Iterator i = Iterators.filter(theProps.keys(), + theFieldFilter); + i.hasNext();) { + String propName = (String)i.next(); + + if (theNameAlias != null) { + sb.append(theNameAlias) + .append('.'); + } + sb.append('`') + .append(propName) + .append('`') + .append(theAssignmentOp) + .append(" {") + .append(theValueAlias) + .append("}.") + .append('`') + .append(propName) + .append('`') + .append(theRelationOp); + } + return sb.substring(0, sb.length() - theRelationOp.length()); + } + + public static String literalMap(JSONObject theProps, + String theAlias) { + return literalMap(theProps, null, theAlias, ":", ",", f -> true); + } + +} + diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxies.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxies.java new file mode 100644 index 0000000..8983599 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxies.java @@ -0,0 +1,37 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.Map; +import java.lang.reflect.ParameterizedType; + +import org.json.JSONObject; + +import org.onap.sdc.dcae.catalog.commons.ProxyBuilder; + + +public class Proxies { + + private Proxies() { + } + + + private static ProxyBuilder builder = new ProxyBuilder(); + + public static T build(Map theData, Class theType) { + return builder.build(new JSONObject(theData), theType); + } + + public static T build(Map theData, Map theContextData, Class theType) { + return builder.build(new JSONObject(theData), theContextData, theType); + } + + public static T build(JSONObject theData, Class theType) { + return builder.build(theData, theType); + } + + public static Class typeArgument(Class theType) { + return (Class) + ((ParameterizedType)theType.getGenericSuperclass()). + getActualTypeArguments()[0]; + } + +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxy.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxy.java new file mode 100644 index 0000000..d368886 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxy.java @@ -0,0 +1,144 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.List; +import java.util.LinkedList; +import java.util.Map; +import java.util.Collections; + +import java.util.stream.Collectors; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import java.lang.reflect.Type; +import java.lang.reflect.Method; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; + +import java.lang.invoke.MethodHandles; + +import com.google.common.reflect.Invokable; +import org.onap.sdc.dcae.catalog.commons.Proxy; +import org.onap.sdc.dcae.catalog.commons.ProxyBuilder; +import com.google.common.reflect.AbstractInvocationHandler; + +import org.apache.commons.beanutils.ConvertUtils; + +import org.json.JSONObject; +import org.json.JSONArray; + +public class Proxy extends AbstractInvocationHandler { + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + + public static @interface DataMap { + + public String map() default ""; + + public boolean proxy() default false; + + public Class elementType() default Void.class; + } + + + public static final Constructor lookupHandleConstructor; + + static { + try { + lookupHandleConstructor = + MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, + int.class); + + if (!lookupHandleConstructor.isAccessible()) { + lookupHandleConstructor.setAccessible(true); + } + } + catch (Exception x) { + throw new RuntimeException(x); + } + } + + + private JSONObject data; + private ProxyBuilder builder; + + protected Proxy(JSONObject theData, ProxyBuilder theBuilder) { + this.data = theData; + this.builder = theBuilder; + } + + public JSONObject data() { + return this.data; + } + + public ProxyBuilder getBuilder() { + return this.builder; + } + + protected Object handleInvocation( + Object theProxy,Method theMethod,Object[] theArgs) + throws Throwable { + if (theMethod.isDefault()) { + final Class declaringClass = theMethod.getDeclaringClass(); + + return lookupHandleConstructor + .newInstance(declaringClass, MethodHandles.Lookup.PRIVATE) + .unreflectSpecial(theMethod, declaringClass) + .bindTo(theProxy) + .invokeWithArguments(theArgs); + } + + String key = theMethod.getName(); + + Proxy.DataMap dataMap = (Proxy.DataMap)theMethod.getAnnotation(Proxy.DataMap.class); + if (dataMap != null) { + String dataKey = dataMap.map(); + if (dataKey != null && !"".equals(dataKey)) + key = dataKey; + } + + //this is ugly, can this be done through an extension mechanism such as plugging in functions? + if ( builder.hasExtension(key) ) + return this.builder.extension(key).apply(this, theArgs); + + //we give priority to the context (because of the 'catalog' property issue in catalog service) but + //how natural is this? + Object val = this.builder.context(key); + if (val == null) + val = this.data.opt(key); + + if (val == null) + return null; + +//as we create proxies here we should store them back in the 'data' so that we do not do it again +//can we always 'recognize' them? + if (val instanceof String && + String.class != theMethod.getReturnType()) { + //??This will yield a POJO .. + return ConvertUtils.convert((String)val, theMethod.getReturnType()); + } + else if (val instanceof JSONObject) { + if (dataMap != null && dataMap.proxy()) { + return builder.build((JSONObject)val, theMethod.getReturnType()); + } + } + else if (val instanceof JSONArray&& dataMap != null && + dataMap.proxy() && + List.class.isAssignableFrom(theMethod.getReturnType())) { + + List res = (List) theMethod.getReturnType().newInstance(); + for (int i = 0; i < ((JSONArray) val).length(); i++) { + res.add(builder.build(((JSONArray) val).getJSONObject(i), dataMap.elementType())); + } + return res; + + } + return val; + } +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxy.pojo b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxy.pojo new file mode 100644 index 0000000..b3b5cb9 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxy.pojo @@ -0,0 +1,145 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.List; +import java.util.Map; +import java.util.Collections; + +import java.util.stream.Collectors; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import java.lang.reflect.Type; +import java.lang.reflect.Method; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; + +import java.lang.invoke.MethodHandles; + +import com.google.common.reflect.Invokable; +import com.google.common.reflect.AbstractInvocationHandler; + +import org.apache.commons.beanutils.ConvertUtils; + + +/** + */ +public class Proxy + extends AbstractInvocationHandler { + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + + public static @interface DataMap { + + public String map() default ""; + + public boolean proxy() default false; + + public Class elementType() default Void.class; + } + + + public static Constructor lookupHandleConstructor; + + static { + try { + lookupHandleConstructor = + MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, + int.class); + + if (!lookupHandleConstructor.isAccessible()) { + lookupHandleConstructor.setAccessible(true); + } + } + catch (Exception x) { + throw new RuntimeException(x); + } + } + + + private Map data; + private ProxyBuilder builder; + + protected Proxy(Map theData, ProxyBuilder theBuilder) { + this.data = theData; + this.builder = theBuilder; + } + + public Map data() { + return this.data; + } + + public ProxyBuilder getBuilder() { + return this.builder; + } + + protected Object handleInvocation( + Object theProxy,Method theMethod,Object[] theArgs) + throws Throwable { + if (theMethod.isDefault()) { + final Class declaringClass = theMethod.getDeclaringClass(); + /* + return MethodHandles.lookup() + .in(declaringClass) + .unreflectSpecial(theMethod, declaringClass) + .bindTo(theProxy) + .invokeWithArguments(theArgs); + */ + return lookupHandleConstructor + .newInstance(declaringClass, MethodHandles.Lookup.PRIVATE) + .unreflectSpecial(theMethod, declaringClass) + .bindTo(theProxy) + .invokeWithArguments(theArgs); + } + + String key = theMethod.getName(); + + Proxy.DataMap dataMap = (Proxy.DataMap)theMethod.getAnnotation(Proxy.DataMap.class); + if (dataMap != null) { + String dataKey = dataMap.map(); + if (dataKey != null && !"".equals(dataKey)) + key = dataKey; + } + + //this is ugly, can this be done through an extension mechanism such as plugging in functions? + if ( builder.hasExtension(key) ) + return this.builder.extension(key).apply(this, theArgs); + + Object val = this.data.getOrDefault(key, this.builder.context(key)); + +System.out.println("!! " + key + " : " + val); + +//as we create proxies here we should store them back in the 'data' so that we do not do it again +//can we always 'recognize' them? + if (val instanceof String && + String.class != theMethod.getReturnType()) { + return ConvertUtils.convert((String)val, theMethod.getReturnType()); + } + else if (val instanceof Map) { + if (dataMap != null && dataMap.proxy()) { + return builder.build((Map)val, theMethod.getReturnType()); + } + } + else if (val instanceof List) { + if (dataMap != null && dataMap.proxy()) { + return ((List)val) + .stream() + .map(e -> this.builder.build((Map)e, dataMap.elementType())) + .collect(Collectors.toList()); + } + } +/* + else if (val.getClass().isArray()) { + if (dataMap != null && dataMap.proxy()) { + } + } +*/ + return val; + } +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/ProxyBuilder.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/ProxyBuilder.java new file mode 100644 index 0000000..e3a422a --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/ProxyBuilder.java @@ -0,0 +1,92 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.util.Map; + +import java.util.function.Function; +import java.util.function.BiFunction; + +import org.apache.commons.beanutils.ConvertUtils; +import org.apache.commons.beanutils.Converter; + +import org.json.JSONObject; + +import org.onap.sdc.dcae.catalog.commons.Proxy; +import org.onap.sdc.dcae.catalog.commons.ProxyBuilder; + + +public class ProxyBuilder { + + private Map context; + private Map> extensions; + + public ProxyBuilder() { + } +/* + public T build(Map theData, Class theType) { + return build(theData, this.context, theType); + } + + public T build(Map theData, Map theContextData, Class theType) { + return (T)java.lang.reflect.Proxy.newProxyInstance( + ProxyBuilder.class.getClassLoader(), + new Class[] { theType }, + new Proxy(theData, this)); + } +*/ + public T build(Map theData, Class theType) { + return build(new JSONObject(theData), theType); + } + + public T build(Map theData, Map theContextData, Class theType) { + return build(new JSONObject(theData), theContextData, theType); + } + + public T build(JSONObject theData, Class theType) { + return build(theData, this.context, theType); + } + + public T build(JSONObject theData, Map theContextData, Class theType) { + return (T)java.lang.reflect.Proxy.newProxyInstance( + ProxyBuilder.class.getClassLoader(), + new Class[] { theType }, + new Proxy(theData, this)); + } + + + + + public ProxyBuilder withConverter(final Function theConverter, Class theType) { + ConvertUtils.register(new Converter() { + public Object convert(Class theToType, Object theValue) { + return theConverter.apply(theValue); + } + }, + theType); + return this; + } + + /* + plug in an extension to the proxy default behaviour. + */ + public ProxyBuilder withExtensions(Map> theExtensions) { + this.extensions = theExtensions; + return this; + } + + public ProxyBuilder withContext(Map theContext) { + this.context = theContext; + return this; + } + + protected Object context(String theName) { + return this.context == null ? null : this.context.get(theName); + } + + protected BiFunction extension(String theName) { + return this.extensions == null ? null : this.extensions.get(theName); + } + + protected boolean hasExtension(String theName) { + return this.extensions == null ? false : this.extensions.containsKey(theName); + } +} diff --git a/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Recycler.java b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Recycler.java new file mode 100644 index 0000000..3493cb1 --- /dev/null +++ b/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Recycler.java @@ -0,0 +1,329 @@ +package org.onap.sdc.dcae.catalog.commons; + +import java.io.Reader; +import java.io.IOException; + +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Collections; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.apache.commons.jxpath.Pointer; +import org.apache.commons.jxpath.JXPathContext; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.type.TypeReference; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.yaml.snakeyaml.Yaml; + + +/** + * Practically a copy of the Validator's service Recycler, minus the Spring framework aspects + picking up the + * description of every node + */ +public class Recycler { + + private static final String PROPERTIES = "properties"; + private static final String VALUE = "value"; + private static final String ASSIGNMENT = "assignment"; + private static final String CAPABILITY = "capability"; + private static final String RELATIONSHIP = "relationship"; + private static final String NAME = "name"; + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + private List imports; + private List metas; + + public Recycler() { + withImports(); + withMetas(null); + } + + public Recycler withImports(String... theImports) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Setting imports to {}", theImports); + ListBuilder importsBuilder = new ListBuilder(); + for (int i = 0; i < theImports.length; i++) { + importsBuilder.add(new MapBuilder() + .put("i" + i, theImports[i]) + .build()); + } + this.imports = importsBuilder.build(); + return this; + } + + private List imports() { + ListBuilder importsBuilder = new ListBuilder(); + for (Map e: this.imports) { + importsBuilder.add(new MapBuilder() + .putAll(e) + .build()); + } + return importsBuilder.build(); + } + + public Recycler withMetas(String... theMetas) { + this.metas = (theMetas == null) ? Collections.emptyList() : Arrays.asList(theMetas); + return this; + } + + public Object recycle(final Reader theSource) throws Exception { + return this.recycle(new ObjectMapper().readValue(theSource, (Class)HashMap.class)); + } + + public Object recycle(final Object theDump) { + + final JXPathContext jxroot = JXPathContext.newContext(theDump); + jxroot.setLenient(true); + + final Map nodeTemplates = + (Map)new MapBuilder() + .putAll( + StreamSupport + .stream( + Spliterators.spliteratorUnknownSize((Iterator)jxroot.iteratePointers("/nodes"), 16), false) + .map(p -> { + JXPathContext jxnode = jxroot.getRelativeContext(p); + return new AbstractMap.SimpleEntry( + (String)jxnode.getValue(NAME) + "_" + (String)jxnode.getValue("nid"), + new MapBuilder() + .put("type", jxnode.getValue("type/name")) + .put("description", jxnode.getValue("description")) + .putOpt("metadata", nodeMetadata(jxnode)) + .putOpt(PROPERTIES, nodeProperties(jxnode)) + .putOpt("requirements", nodeRequirements(jxnode)) + .putOpt("capabilities", nodeCapabilities(jxnode)) + .build()); + })::iterator) + .buildOpt(); + + return new MapBuilder() + .put("tosca_definitions_version", "tosca_simple_yaml_1_0_0") + .put("imports", imports()) + .put("topology_template", new MapBuilder() + .putOpt("node_templates", nodeTemplates) + .build()) + .build(); + } + + /* */ + private Object nodeProperties(JXPathContext theNodeContext) { + return + new MapBuilder() + .putAll( + StreamSupport.stream( + Spliterators.spliteratorUnknownSize((Iterator)theNodeContext.iterate(PROPERTIES), 16), false) + .map(m -> new AbstractMap.SimpleEntry(m.get(NAME), this.nodeProperty(m))) + .filter(e -> e.getValue() != null) + ::iterator) + .buildOpt(); + } + + /* */ + private Object nodeProperty(final Map theSpec) { + Object value = theSpec.get(VALUE); + if (value == null) { + value = theSpec.get("default"); + if (value == null) { + /*final*/ Map assign = (Map)theSpec.get(ASSIGNMENT); + if (assign != null) { + value = assign.get(VALUE); + } + } + } + String type = (String)theSpec.get("type"); + if (value != null && type != null) { + value = getValueByType(value, type); + } + return value; + } + + private Object getValueByType(Object value, String type) { + Object returnValue = null; + try { + if ("map".equals(type) && !(value instanceof Map)) { + returnValue = new ObjectMapper().readValue(value.toString(), new TypeReference(){}); + } + else if ("list".equals(type) && !(value instanceof List)) { + returnValue = new ObjectMapper().readValue(value.toString(), new TypeReference(){}); + } + else if ("integer".equals(type) && (value instanceof String)) { + returnValue = Integer.valueOf((String)value); + } + else if ("float".equals(type) && (value instanceof String)) { + returnValue = Double.valueOf((String)value); //double because that's how the yaml parser would encode it + } + } + catch (NumberFormatException nfx) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Failed to process String representation {} of numeric data: {}", value, nfx); + } + catch (IOException iox) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Failed to process {} representation of a collection: {}", value.getClass().getName(), iox); + } + return returnValue; + } + + /* */ + private List nodeRequirements(JXPathContext theNodeContext) { + return + new ListBuilder() + .addAll( + StreamSupport.stream( + Spliterators.spliteratorUnknownSize((Iterator)theNodeContext.iterate("requirements"), 16), false) + .flatMap(m -> this.nodeRequirement(m, theNodeContext).stream()) + //nicer that the ListBuilder buy cannot handle the empty lists, i.e. it will generate empty requirement lists + // .collect(Collectors.toList()) + .toArray()) + .buildOpt(); + } + + /* + * @param theSpec the requirement entry that appears within the node specification + * @param theNodeContext .. Should I pass the root context instead of assuming that the nodes context has it as parent? + * @return a List as one requirement (definition) could end up being instantiated multiple times + */ + private List nodeRequirement(final Map theSpec, JXPathContext theNodeContext/*Iterator theTargets*/) { + + final ListBuilder value = new ListBuilder(); + + final Map target = (Map)theSpec.get("target"); + final Map capability = (Map)theSpec.get(CAPABILITY); + final Map relationship = (Map)theSpec.get(RELATIONSHIP); + + //this are actual assignments + for (Iterator i = theNodeContext.getParentContext().iterate("/relations[@n2='" + theNodeContext.getValue("nid") + "']/meta[@p2='" + theSpec.get(NAME) +"']"); i.hasNext(); ) { + + String targetNodeName = (String)((Map)i.next()).get("n1"); + + //make sure target exists + Map targetNode = (Map)theNodeContext.getParentContext().getValue("/nodes[@nid='" + targetNodeName + "']"); + if (null == targetNode) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Relation points to non-existing node {}", targetNodeName); + continue; //this risks of producing a partial template .. + } + + value.add(new MapBuilder().put(theSpec.get(NAME), new MapBuilder() + .putOpt("node", targetNode.get(NAME) + "_" + targetNode.get("nid")) + .putOpt(CAPABILITY, capability == null ? null : capability.get(NAME)) + .putOpt(RELATIONSHIP, relationship == null ? null : relationship.get("type")) + .build()).build()); + } + addTemporary(theSpec, theNodeContext, value, capability, relationship); + + if (value.isEmpty()) { + value.add(new MapBuilder().put(theSpec.get(NAME), new MapBuilder() + .putOpt("node", target == null ? null : target.get(NAME) + "_" + target.get("nid")) + .putOpt(CAPABILITY, capability == null ? null : capability.get(NAME)) + .putOpt(RELATIONSHIP, relationship == null ? null : relationship.get("type")) + .build()).build()); + } + + return value.build(); + } + + private void addTemporary(Map theSpec, JXPathContext theNodeContext, ListBuilder value, Map capability, Map relationship) { + //temporary + for (Iterator i = theNodeContext.getParentContext().iterate("/relations[@n1='" + theNodeContext.getValue("nid") + "']/meta[@p1='" + theSpec.get(NAME) +"']"); i.hasNext(); ) { + + String targetNodeName = (String)((Map)i.next()).get("n2"); + + Map targetNode = (Map)theNodeContext.getParentContext().getValue("/nodes[@nid='" + targetNodeName + "']"); + //make sure target exists + if (null == targetNode) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Relation points to non-existing node {}", targetNode); + continue; //this risks of producing a partial template .. + } + + value.add(new MapBuilder().put(theSpec.get(NAME), new MapBuilder() + .putOpt("node", targetNode.get(NAME) + "_" + targetNode.get("nid")) + .putOpt(CAPABILITY, capability == null ? null : capability.get(NAME)) + .putOpt(RELATIONSHIP, relationship == null ? null : relationship.get("type")) + .build()).build()); + } + //end temporary + } + + /* */ + private Map nodeCapabilities(JXPathContext theNodeContext) { + return + new MapBuilder() + .putAll( + StreamSupport.stream( + Spliterators.spliteratorUnknownSize((Iterator)theNodeContext.iterate("capabilities"), 16), false) + .map(m -> this.nodeCapability(m)) + .filter(c -> c != null) + ::iterator) + .buildOpt(); + } + + /** + * this handles a capability assignment which only includes properties and attributes so unless there + * are any properties/attributes assignments we might not generate anything + */ + private Map.Entry nodeCapability(final Map theSpec) { + List properties = (List) theSpec.get(PROPERTIES); + if (properties == null || properties.isEmpty()) { + return null; + } + + return new AbstractMap.SimpleEntry(theSpec.get(NAME), + new MapBuilder() + .put(PROPERTIES, + new MapBuilder().putAll(properties.stream() + .filter(p -> p.containsKey(ASSIGNMENT) || + p.containsKey(VALUE)) + .map(p -> new AbstractMap.SimpleEntry( + p.get(NAME), + p.containsKey(ASSIGNMENT) ? + ((Map) p.get(ASSIGNMENT)).get(VALUE) + : p.get(VALUE)) + ) + ::iterator) + .build()) + .build()); + } + + + /* */ + private Object nodeMetadata(JXPathContext theNodeContext) { + return + new MapBuilder() + .putAll( + this.metas + .stream() + .flatMap(m -> { + Object v = theNodeContext.getValue(m); + if (v == null) { + return Stream.empty(); + } + if (v instanceof Map) { + return ((Map) v).entrySet() + .stream() + .map(e -> new AbstractMap.SimpleEntry + (((Map.Entry) e).getKey().toString(), + ((Map.Entry) e).getValue().toString())); + } + return Stream.of(new AbstractMap.SimpleEntry(m, v.toString())); + }) + ::iterator) + .buildOpt(); + } + + + public static String toString(Object theVal) { + return new Yaml().dump(theVal); + } + + + public static void main(String[] theArgs) throws Exception { + debugLogger.log(LogLevel.DEBUG, Recycler.class.getName(), + Recycler.toString( + new Recycler().recycle(new java.io.FileReader(theArgs[0])))); + } +} -- cgit 1.2.3-korg