summaryrefslogtreecommitdiffstats
path: root/env/src/main/java/com/att/inno/env/util
diff options
context:
space:
mode:
Diffstat (limited to 'env/src/main/java/com/att/inno/env/util')
-rw-r--r--env/src/main/java/com/att/inno/env/util/Chrono.java308
-rw-r--r--env/src/main/java/com/att/inno/env/util/DoubleOutputStream.java99
-rw-r--r--env/src/main/java/com/att/inno/env/util/IndentPrintWriter.java115
-rw-r--r--env/src/main/java/com/att/inno/env/util/Pool.java396
-rw-r--r--env/src/main/java/com/att/inno/env/util/RefreshableThreadObject.java126
-rw-r--r--env/src/main/java/com/att/inno/env/util/Split.java91
-rw-r--r--env/src/main/java/com/att/inno/env/util/StringBuilderOutputStream.java180
-rw-r--r--env/src/main/java/com/att/inno/env/util/StringBuilderWriter.java174
8 files changed, 1489 insertions, 0 deletions
diff --git a/env/src/main/java/com/att/inno/env/util/Chrono.java b/env/src/main/java/com/att/inno/env/util/Chrono.java
new file mode 100644
index 0000000..7d81d3d
--- /dev/null
+++ b/env/src/main/java/com/att/inno/env/util/Chrono.java
@@ -0,0 +1,308 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.inno.env.util;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.security.SecureRandom;
+import java.util.TimeZone;
+import java.util.UUID;
+import java.util.logging.Formatter;
+import java.util.logging.LogRecord;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+public class Chrono {
+ private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L;
+
+ public final static DateFormat dateFmt, dateOnlyFmt, niceDateFmt, utcFmt;
+ // Give general access to XML DataType Factory, since it's pretty common
+ public static final DatatypeFactory xmlDatatypeFactory;
+
+ static {
+ try {
+ xmlDatatypeFactory = DatatypeFactory.newInstance();
+ } catch (DatatypeConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+ dateOnlyFmt = new SimpleDateFormat("yyyy-MM-dd");
+ niceDateFmt = new SimpleDateFormat("yyyy/MM/dd HH:mm zzz");
+ dateFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+ utcFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+ utcFmt.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+
+
+ public static class Formatter8601 extends Formatter {
+
+ @Override
+ public String format(LogRecord r) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(dateFmt.format(new Date(r.getMillis())));
+ sb.append(' ');
+ sb.append(r.getThreadID());
+ sb.append(' ');
+ sb.append(r.getLevel());
+ sb.append(": ");
+ sb.append(r.getMessage());
+ sb.append('\n');
+ return sb.toString();
+ }
+
+ }
+
+ /**
+ * timeStamp
+ *
+ * Convenience method to setup an XML dateTime (XMLGregorianCalendar) with "now"
+ * @return
+ */
+ public static XMLGregorianCalendar timeStamp() {
+ return xmlDatatypeFactory.newXMLGregorianCalendar(new GregorianCalendar());
+ }
+
+ /**
+ * timestamp
+ *
+ * Convenience method to setup an XML dateTime (XMLGregorianCalendar) with passed in Date
+ * @param date
+ * @return
+ */
+ public static XMLGregorianCalendar timeStamp(Date date) {
+ GregorianCalendar gc = new GregorianCalendar();
+ gc.setTime(date);
+ return xmlDatatypeFactory.newXMLGregorianCalendar(gc);
+ }
+
+ public static XMLGregorianCalendar timeStamp(GregorianCalendar gc) {
+ return xmlDatatypeFactory.newXMLGregorianCalendar(gc);
+ }
+
+ public static String utcStamp() {
+ return utcFmt.format(new Date());
+ }
+
+ public static String utcStamp(Date date) {
+ if(date==null)return "";
+ return utcFmt.format(date);
+ }
+
+ public static String utcStamp(GregorianCalendar gc) {
+ if(gc==null)return "";
+ return utcFmt.format(gc.getTime());
+ }
+
+ public static String utcStamp(XMLGregorianCalendar xgc) {
+ if(xgc==null)return "";
+ return utcFmt.format(xgc.toGregorianCalendar().getTime());
+ }
+
+ public static String dateStamp() {
+ return dateFmt.format(new Date());
+ }
+
+ public static String dateStamp(GregorianCalendar gc) {
+ if(gc == null)return "";
+ return dateFmt.format(gc.getTime());
+ }
+
+ public static String dateStamp(Date date) {
+ if(date == null)return "";
+ return dateFmt.format(date);
+ }
+
+ public static String dateStamp(XMLGregorianCalendar xgc) {
+ if(xgc==null)return "";
+ return dateFmt.format(xgc.toGregorianCalendar().getTime());
+ }
+
+ /**
+ * JAXB compatible dataTime Stamp
+ *
+ * Java 6 does not format Timezone with -05:00 format, and JAXB XML breaks without it.
+ *
+ * @return
+ */
+ public static String dateTime() {
+ return dateTime(new GregorianCalendar());
+ }
+
+ /**
+ * JAXB compatible dataTime Stamp
+ *
+ * Java 6 does not format Timezone with -05:00 format, and JAXB XML breaks without it.
+ *
+ * @return
+ */
+ public static String dateTime(Date date) {
+ GregorianCalendar gc = new GregorianCalendar();
+ gc.setTime(date);
+ return dateTime(gc);
+ }
+
+ /**
+ * JAXB compatible dataTime Stamp
+ *
+ * Java 6 does not format Timezone with -05:00 format, and JAXB XML breaks without it.
+ *
+ * @return
+ */
+ public static String dateTime(GregorianCalendar gc) {
+ if(gc == null)return "";
+ TimeZone tz = gc.getTimeZone();
+ int tz1 = (tz.getRawOffset()+tz.getDSTSavings())/0x8CA0;
+ int tz1abs = Math.abs(tz1);
+ return String.format("%04d-%02d-%02dT%02d:%02d:%02d.%03d%c%02d:%02d",
+ gc.get(GregorianCalendar.YEAR),
+ gc.get(GregorianCalendar.MONTH)+1,
+ gc.get(GregorianCalendar.DAY_OF_MONTH),
+ gc.get(GregorianCalendar.HOUR),
+ gc.get(GregorianCalendar.MINUTE),
+ gc.get(GregorianCalendar.SECOND),
+ gc.get(GregorianCalendar.MILLISECOND),
+ tz1==tz1abs?'+':'-',
+ tz1abs/100,
+ ((tz1abs-(tz1abs/100)*100)*6)/10 // Get the "10s", then convert to mins (without losing int place)
+ );
+ }
+
+ /**
+ * JAXB compatible dataTime Stamp
+ *
+ * Java 6 does not format Timezone with -05:00 format, and JAXB XML breaks without it.
+ *
+ * @return
+ */
+ public static String dateTime(XMLGregorianCalendar xgc) {
+ return xgc==null?"":dateTime(xgc.toGregorianCalendar());
+ }
+
+ public static String dateOnlyStamp() {
+ return dateOnlyFmt.format(new Date());
+ }
+
+ public static String dateOnlyStamp(GregorianCalendar gc) {
+ return gc == null?"":dateOnlyFmt.format(gc.getTime());
+ }
+
+ public static String dateOnlyStamp(Date date) {
+ return date == null?"":dateOnlyFmt.format(date);
+ }
+
+ public static String dateOnlyStamp(XMLGregorianCalendar xgc) {
+ return xgc==null?"":dateOnlyFmt.format(xgc.toGregorianCalendar().getTime());
+ }
+
+ public static String niceDateStamp() {
+ return niceDateFmt.format(new Date());
+ }
+
+ public static String niceDateStamp(Date date) {
+ return date==null?"":niceDateFmt.format(date);
+ }
+
+ public static String niceDateStamp(GregorianCalendar gc) {
+ return gc==null?"":niceDateFmt.format(gc.getTime());
+ }
+
+ public static String niceDateStamp(XMLGregorianCalendar xgc) {
+ return xgc==null?"":niceDateFmt.format(xgc.toGregorianCalendar().getTime());
+ }
+
+
+ ////////////////////// HELPFUL Strings
+ public static final String BAD_DIR_CHARS_REGEX = "[/:\\;.]";
+ public static final String SPLIT_DIR_REGEX = "/";
+
+ public static long firstMomentOfDay(long utc) {
+ GregorianCalendar begin = new GregorianCalendar();
+ begin.setTimeInMillis(utc);
+ return firstMomentOfDay(begin).getTimeInMillis();
+ }
+
+ public static long lastMomentOfDay(long utc) {
+ GregorianCalendar end = new GregorianCalendar();
+ end.setTimeInMillis(utc);
+ return lastMomentOfDay(end).getTimeInMillis();
+ }
+
+ public static GregorianCalendar firstMomentOfDay(GregorianCalendar begin) {
+ if(begin==null)begin = new GregorianCalendar();
+ begin.set(GregorianCalendar.HOUR, 0);
+ begin.set(GregorianCalendar.AM_PM, GregorianCalendar.AM);
+ begin.set(GregorianCalendar.MINUTE, 0);
+ begin.set(GregorianCalendar.SECOND, 0);
+ begin.set(GregorianCalendar.MILLISECOND, 0);
+ return begin;
+ }
+
+ public static GregorianCalendar lastMomentOfDay(GregorianCalendar end) {
+ if(end==null)end = new GregorianCalendar();
+ end.set(GregorianCalendar.HOUR, 11);
+ end.set(GregorianCalendar.MINUTE, 59);
+ end.set(GregorianCalendar.SECOND, 59);
+ end.set(GregorianCalendar.MILLISECOND, 999);
+ end.set(GregorianCalendar.AM_PM, GregorianCalendar.PM);
+ return end;
+ }
+
+ // UUID needs to be converted from UUID Epoch
+ public static final Date uuidToDate(UUID id) {
+ return new Date((id.timestamp() - NUM_100NS_INTERVALS_SINCE_UUID_EPOCH)/10000);
+ }
+
+ public static final long uuidToUnix(UUID id) {
+ return (id.timestamp() - NUM_100NS_INTERVALS_SINCE_UUID_EPOCH)/10000;
+ }
+
+ public static float millisFromNanos(long start, long end) {
+ return (end - start) / 1000000f;
+ }
+
+
+ private static long sequence = new SecureRandom().nextInt();
+ private static synchronized long sequence() {
+ return ++sequence;
+ }
+ public static final UUID dateToUUID(Date d) {
+ /*
+ * From Cassandra : http://wiki.apache.org/cassandra/FAQ
+ Magic number obtained from #cassandra's thobbs, who
+ claims to have stolen it from a Python library.
+ */
+
+ long origTime = d.getTime();
+ long time = origTime * 10000 + NUM_100NS_INTERVALS_SINCE_UUID_EPOCH;
+ long timeLow = time & 0xffffffffL;
+ long timeMid = time & 0xffff00000000L;
+ long timeHi = time & 0xfff000000000000L;
+ long upperLong = (timeLow << 32) | (timeMid >> 16) | (1 << 12) | (timeHi >> 48) ;
+ return new java.util.UUID(upperLong, (0xC000000000000000L | sequence()));
+ }
+
+}
diff --git a/env/src/main/java/com/att/inno/env/util/DoubleOutputStream.java b/env/src/main/java/com/att/inno/env/util/DoubleOutputStream.java
new file mode 100644
index 0000000..212f0c8
--- /dev/null
+++ b/env/src/main/java/com/att/inno/env/util/DoubleOutputStream.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.inno.env.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class DoubleOutputStream extends OutputStream {
+ private OutputStream[] oss;
+ private boolean[] close;
+
+ /**
+ * Create a Double Stream Writer
+ * Some Streams should not be closed by this object (i.e. System.out), therefore, mark them with booleans
+ */
+ public DoubleOutputStream(OutputStream a, boolean closeA, OutputStream b, boolean closeB) {
+ oss = new OutputStream[] {a,b};
+ close = new boolean[] {closeA,closeB};
+ }
+
+ /**
+ * Write a single character.
+ * @throws IOException
+ */
+ @Override
+ public void write(int c) throws IOException {
+ for(OutputStream os : oss) {
+ os.write(c);
+ }
+ }
+
+ /**
+ * Write a portion of an array of characters.
+ *
+ * @param bbuf Array of characters
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ * @throws IOException
+ */
+ @Override
+ public void write(byte bbuf[], int off, int len) throws IOException {
+ for(OutputStream os : oss) {
+ os.write(bbuf,off,len);
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ for(OutputStream os : oss) {
+ os.write(b);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.OutputStream#close()
+ */
+ @Override
+ public void close() throws IOException {
+ for(int i=0;i<oss.length;++i) {
+ if(close[i]) {
+ oss[i].close();
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.OutputStream#flush()
+ */
+ @Override
+ public void flush() throws IOException {
+ for(OutputStream os : oss) {
+ os.flush();
+ }
+ }
+
+
+
+}
diff --git a/env/src/main/java/com/att/inno/env/util/IndentPrintWriter.java b/env/src/main/java/com/att/inno/env/util/IndentPrintWriter.java
new file mode 100644
index 0000000..48c5243
--- /dev/null
+++ b/env/src/main/java/com/att/inno/env/util/IndentPrintWriter.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.inno.env.util;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ *
+ * Catch \n and indent according to current indent levels of JavaGen
+ */
+public class IndentPrintWriter extends PrintWriter {
+ public static int INDENT = 2;
+ private boolean addIndent;
+ private int indent;
+ private int col;
+
+ public IndentPrintWriter(Writer out) {
+ super(out);
+ addIndent = false;
+ indent = col = 0;
+ }
+
+ public IndentPrintWriter(OutputStream out) {
+ super(out);
+ addIndent = false;
+ indent = col = 0;
+ }
+
+
+ public void write(String str) {
+ int len = str.length();
+ for(int i=0;i<len;++i) {
+ write((int)str.charAt(i));
+ }
+ }
+
+ public void println() {
+ write((int)'\n');
+ }
+ public void write(String str, int off, int len) {
+ len = Math.min(str.length(),off+len);
+ for(int i=off;i<len;++i) {
+ write((int)str.charAt(i));
+ }
+ }
+ public void write(int b) {
+ if (b == '\n') {
+ addIndent = true;
+ col = 0;
+ } else if (addIndent) {
+ addIndent = false;
+ toIndent();
+ } else {
+ ++col;
+ }
+ super.write(b);
+ }
+
+ @Override
+ public void write(char[] buf, int off, int len) {
+ for (int i = 0; i < len; ++i)
+ write(buf[i] + off);
+ }
+
+ public void setIndent(int size) {
+ indent = size;
+ }
+
+ public void inc() {
+ ++indent;
+ }
+
+ public void dec() {
+ --indent;
+ }
+
+ public void toCol(int idx) {
+ while(idx>col++)super.write((int)' ');
+ }
+
+ public int getIndent() {
+ return indent;
+ }
+
+ public void toIndent() {
+ int end = indent * INDENT;
+ for (int i = 0; i < end; ++i) {
+ super.write((int) ' ');
+ }
+ col = end;
+ }
+}
diff --git a/env/src/main/java/com/att/inno/env/util/Pool.java b/env/src/main/java/com/att/inno/env/util/Pool.java
new file mode 100644
index 0000000..e631c98
--- /dev/null
+++ b/env/src/main/java/com/att/inno/env/util/Pool.java
@@ -0,0 +1,396 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+/*
+ * Pool
+ *
+ * 5/27/2011
+ */
+package com.att.inno.env.util;
+
+import java.util.LinkedList;
+
+import com.att.inno.env.APIException;
+import com.att.inno.env.LogTarget;
+
+/**
+ * This Class pools on an As-Needed-Basis any particular kind of class, which is
+ * quite suitable for expensive operations.
+ *
+ * The user calls "get" on a Pool, and if a waiting resource (T) is available,
+ * it will be returned. Otherwise, one will be created with the "Creator" class
+ * (must be defined for (T)).
+ *
+ * You can Prime the instances to avoid huge startup costs
+ *
+ * The returned "Pooled" object simply has to call "done()" and the object is
+ * returned to the pool. If the developer does not return the object, a memory
+ * leak does not occur. There are no references to the object once "get" is
+ * called. However, the developer who does not return the object when done
+ * obviates the point of the pool, as new Objects are created in place of the
+ * Object not returned when another call to "get" is made.
+ *
+ * There is a cushion of extra objects, currently defaulted to MAX_RANGE. If the
+ * items returned become higher than the MAX_RANGE, the object is allowed to go
+ * out of scope, and be cleaned up. the default can be changed on a per-pool
+ * basis.
+ *
+ *
+ *
+ * @param <T>
+ */
+public class Pool<T> {
+ /**
+ * This is a constant which specified the default maximum number of unused
+ * objects to be held at any given time.
+ */
+ private static final int MAX_RANGE = 6; // safety
+
+ /**
+ * only Simple List needed.
+ *
+ * NOTE TO MAINTAINERS: THIS OBJECT DOES IT'S OWN SYNCHRONIZATION. All
+ * changes that touch list must account for correctly synchronizing list.
+ */
+ private LinkedList<Pooled<T>> list;
+
+ /**
+ * keep track of how many elements exist, to avoid asking list.
+ */
+ private int count;
+
+ /**
+ * Spares are those Object that are primed and ready to go.
+ */
+ private int spares;
+
+ /**
+ * Actual MAX number of spares allowed to hang around. Can be set to
+ * something besides the default MAX_RANGE.
+ */
+ private int max_range = MAX_RANGE;
+
+ /**
+ * The Creator for this particular pool. It must work for type T.
+ */
+ private Creator<T> creator;
+
+ /**
+ * Create a new Pool, given the implementation of Creator<T>, which must be
+ * able to create/destroy T objects at will.
+ *
+ * @param creator
+ */
+ public Pool(Creator<T> creator) {
+ count = spares = 0;
+ this.creator = creator;
+ list = new LinkedList<Pooled<T>>();
+ }
+
+ /**
+ * Preallocate a certain number of T Objects. Useful for services so that
+ * the first transactions don't get hit with all the Object creation costs
+ *
+ * @param lt
+ * @param prime
+ * @throws APIException
+ */
+ public void prime(LogTarget lt, int prime) throws APIException {
+ for (int i = 0; i < prime; ++i) {
+ Pooled<T> pt = new Pooled<T>(creator.create(), this, lt);
+ synchronized (list) {
+ list.addFirst(pt);
+ ++count;
+ }
+ }
+
+ }
+
+ /**
+ * Destroy and remove all remaining objects. This is valuable for closing
+ * down all Allocated objects cleanly for exiting. It is also a good method
+ * for removing objects when, for instance, all Objects are invalid because
+ * of broken connections, etc.
+ */
+ public void drain() {
+ synchronized (list) {
+ for (int i = 0; i < list.size(); ++i) {
+ Pooled<T> pt = list.remove();
+ creator.destroy(pt.content);
+ pt.logTarget.log("Pool drained ", creator.toString());
+ }
+ count = spares = 0;
+ }
+
+ }
+
+ /**
+ * This is the essential function for Pool. Get an Object "T" inside a
+ * "Pooled<T>" object. If there is a spare Object, then use it. If not, then
+ * create and pass back.
+ *
+ * This one uses a Null LogTarget
+ *
+ * IMPORTANT: When the use of this object is done (and the object is still
+ * in a valid state), then "done()" should be called immediately to allow
+ * the object to be reused. That is the point of the Pool...
+ *
+ * If the Object is in an invalid state, then "toss()" should be used so the
+ * Pool doesn't pass on invalid objects to others.
+ *
+ * @param lt
+ * @return
+ * @throws APIException
+ */
+ public Pooled<T> get() throws APIException {
+ Pooled<T> pt;
+ synchronized (list) {
+ if (list.isEmpty()) {
+ pt = null;
+ } else {
+ pt = list.removeLast();
+ --count;
+ creator.reuse(pt.content);
+ }
+ }
+ if (pt == null) {
+ if (spares < max_range)
+ ++spares;
+ pt = new Pooled<T>(creator.create(), this, LogTarget.NULL);
+ } else {
+ if (spares > 1)
+ --spares;
+ }
+ return pt;
+ }
+
+ /**
+ * This is the essential function for Pool. Get an Object "T" inside a
+ * "Pooled<T>" object. If there is a spare Object, then use it. If not, then
+ * create and pass back.
+ *
+ * If you don't have access to a LogTarget from Env, use LogTarget.NULL
+ *
+ * IMPORTANT: When the use of this object is done (and the object is still
+ * in a valid state), then "done()" should be called immediately to allow
+ * the object to be reused. That is the point of the Pool...
+ *
+ * If the Object is in an invalid state, then "toss()" should be used so the
+ * Pool doesn't pass on invalid objects to others.
+ *
+ * @param lt
+ * @return
+ * @throws APIException
+ */
+ public Pooled<T> get(LogTarget lt) throws APIException {
+ Pooled<T> pt;
+ synchronized (list) {
+ if (list.isEmpty()) {
+ pt = null;
+ } else {
+ pt = list.remove();
+ --count;
+ creator.reuse(pt.content);
+ }
+ }
+ if (pt == null) {
+ if (spares < max_range)
+ ++spares;
+ pt = new Pooled<T>(creator.create(), this, lt);
+ lt.log("Pool created ", creator.toString());
+ } else {
+ if (spares > 1)
+ --spares;
+ }
+ return pt;
+ }
+
+ /**
+ * This function will validate whether the Objects are still in a usable
+ * state. If not, they are tossed from the Pool. This is valuable to have
+ * when Remote Connections go down, and there is a question on whether the
+ * Pooled Objects are still functional.
+ *
+ * @return
+ */
+ public boolean validate() {
+ boolean rv = true;
+ synchronized (list) {
+ for (Pooled<T> t : list) {
+ if (!creator.isValid(t.content)) {
+ rv = false;
+ t.toss();
+ list.remove(t);
+ }
+ }
+ }
+ return rv;
+ }
+
+ /**
+ * This is an internal method, used only by the Internal Pooled<T> class.
+ *
+ * The Pooled<T> class "offers" it's Object back after use. It is an
+ * "offer", because Pool will simply destroy and remove the object if it has
+ * more than enough spares.
+ *
+ * @param lt
+ * @param used
+ * @return
+ */
+ // Used only by Pooled<T>
+ private boolean offer(LogTarget lt, Pooled<T> used) {
+ if (count < spares) {
+ synchronized (list) {
+ list.addFirst(used);
+ ++count;
+ }
+ lt.log("Pool recovered ", creator.toString());
+ } else {
+ lt.log("Pool destroyed ", creator.toString());
+ creator.destroy(used.content);
+ }
+ return false;
+ }
+
+ /**
+ * The Creator Interface give the Pool the ability to Create, Destroy and
+ * Validate the Objects it is maintaining. Thus, it is a specially written
+ * Implementation for each type.
+ *
+ *
+ * @param <T>
+ */
+ public interface Creator<T> {
+ public T create() throws APIException;
+
+ public void destroy(T t);
+
+ public boolean isValid(T t);
+
+ public void reuse(T t);
+ }
+
+ /**
+ * The "Pooled<T>" class is the transient class that wraps the actual Object
+ * T for API use/ It gives the ability to return ("done()", or "toss()") the
+ * Object to the Pool when processing is finished.
+ *
+ * For Safety, i.e. to avoid memory leaks and invalid Object States, there
+ * is a "finalize" method. It is strictly for when coder forgets to return
+ * the object, or perhaps hasn't covered the case during Exceptions or
+ * Runtime Exceptions with finally (preferred). This should not be
+ * considered normal procedure, as finalize() is called at an undetermined
+ * time during garbage collection, and is thus rather useless for a Pool.
+ * However, we don't want Coding Mistakes to put the whole program in an
+ * invalid state, so if something happened such that "done()" or "toss()"
+ * were not called, the resource is still cleaned up as well as possible.
+ *
+ *
+ * @param <T>
+ */
+ public static class Pooled<T> {
+ public final T content;
+ private Pool<T> pool;
+ protected LogTarget logTarget;
+
+ /**
+ * Create the Wrapping Object Pooled<T>.
+ *
+ * @param t
+ * @param pool
+ * @param logTarget
+ */
+ public Pooled(T t, Pool<T> pool, LogTarget logTarget) {
+ content = t;
+ this.pool = pool;
+ this.logTarget = logTarget;
+ }
+
+ /**
+ * This is the key API for the Pool, as calling "done()" offers this
+ * object back to the Pool for reuse.
+ *
+ * Do not use the Pooled<T> object again after calling "done()".
+ */
+ public void done() {
+ if (pool != null) {
+ pool.offer(logTarget, this);
+ }
+ }
+
+ /**
+ * The user of the Object may discover that the Object t is no longer in
+ * a valid state. Don't put Garbage back in the Refrigerator... Toss it,
+ * if it's no longer valid.
+ *
+ * toss() is also used for draining the Pool, etc.
+ *
+ * toss() will attempt to destroy the Object by using the Creator
+ * Interface.
+ *
+ */
+ public void toss() {
+ if (pool != null) {
+ pool.creator.destroy(content);
+ }
+ // Don't allow finalize to put it back in.
+ pool = null;
+ }
+
+ /**
+ * Just in case someone neglected to offer back object... Do not rely on
+ * this, as there is no specific time when finalize is called, which
+ * rather defeats the purpose of a Pool.
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ if (pool != null) {
+ done();
+ pool = null;
+ }
+ }
+ }
+
+ /**
+ * Get the maximum number of spare objects allowed at any moment
+ *
+ * @return
+ */
+ public int getMaxRange() {
+ return max_range;
+ }
+
+ /**
+ * Set a Max Range for numbers of spare objects waiting to be used.
+ *
+ * No negative numbers are allowed
+ *
+ * @return
+ */
+ public void setMaxRange(int max_range) {
+ // Do not allow negative numbers
+ this.max_range = Math.max(0, max_range);
+ }
+
+}
diff --git a/env/src/main/java/com/att/inno/env/util/RefreshableThreadObject.java b/env/src/main/java/com/att/inno/env/util/RefreshableThreadObject.java
new file mode 100644
index 0000000..78adcb9
--- /dev/null
+++ b/env/src/main/java/com/att/inno/env/util/RefreshableThreadObject.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.inno.env.util;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.att.inno.env.APIException;
+import com.att.inno.env.Creatable;
+import com.att.inno.env.Env;
+import com.att.inno.env.LifeCycle;
+
+
+/**
+ * <h1>RefreshableThreadObject</h1>
+ * This is a ThreadLocal like implementation, but it responds to
+ * the {@link LifeCycle} mechanism for configuration refreshes, and
+ * implements {@link Creatable} (for use in destroy, etc).<p>
+ *
+ * In addition to the Thread instance semantics, it compares when the object
+ * was created versus the last "refresh(env)" call when getting, for the
+ * thread, and if necessary to replace the created object, destroying the
+ * previous.<p>
+ *
+ * In most cases, it's better to use the new "Pool" mechanism, as it deals with
+ * gaining and returning resources on an as needed basis. This, however, remains
+ * in the cases where specific Objects need to be retained to specific Threads.<p>
+ *
+ * There is no way to do this kind of specialized behavior in ThreadLocal.
+ *
+ *
+ * @param <T>
+ */
+public class RefreshableThreadObject<T extends Creatable<T>> {
+ private Map<Thread,T> objs;
+ private long refreshed;
+ private Constructor<T> cnst;
+
+ /**
+ * The passed in class <b>must</b> implement the constructor
+ * <pre>
+ * public MyClass(Env env) {
+ * ...
+ * }
+ * </pre>
+ * @param clss
+ * @throws APIException
+ */
+ public RefreshableThreadObject(Class<T> clss) throws APIException {
+ objs = Collections.synchronizedMap(new HashMap<Thread,T>());
+ try {
+ cnst = clss.getConstructor(new Class[]{Env.class} );
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ }
+
+ /**
+ * Get the "T" class from the current thread
+ *
+ * @param env
+ * @return T
+ * @throws APIException
+ */
+ public T get(Env env) throws APIException {
+ Thread t = Thread.currentThread();
+ T obj = objs.get(t);
+ if(obj==null || refreshed>obj.created()) {
+ try {
+ obj = cnst.newInstance(new Object[]{env});
+ } catch (InvocationTargetException e) {
+ throw new APIException(e.getTargetException());
+ } catch (Exception e) {
+ throw new APIException(e);
+ }
+ T destroyMe = objs.put(t,obj);
+ if(destroyMe!=null) {
+ destroyMe.destroy(env);
+ }
+ }
+ return obj;
+ }
+
+ /**
+ * Mark the timestamp of refreshed.
+ *
+ * @param env
+ */
+ public void refresh(Env env) {
+ refreshed = System.currentTimeMillis();
+ }
+
+ /**
+ * Remove the object from the Thread instances
+ * @param env
+ */
+ public void remove(Env env) {
+ T obj = objs.remove(Thread.currentThread());
+ if(obj!=null)
+ obj.destroy(env);
+ }
+}
diff --git a/env/src/main/java/com/att/inno/env/util/Split.java b/env/src/main/java/com/att/inno/env/util/Split.java
new file mode 100644
index 0000000..a25f36c
--- /dev/null
+++ b/env/src/main/java/com/att/inno/env/util/Split.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.inno.env.util;
+
+/**
+ * Split by Char, optional Trim
+ *
+ * Note: I read the String split and Pattern split code, and we can do this more efficiently for a single Character
+ *
+ * 8/20/2015
+ */
+
+public class Split {
+ public static String[] split(char c, String value) {
+ // Count items to preallocate Array (memory alloc is more expensive than counting twice)
+ int count,idx;
+ for(count=1,idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,++idx),++count);
+ String[] rv = new String[count];
+ if(count==1) {
+ rv[0]=value;
+ } else {
+ int last=0;
+ count=-1;
+ for(idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,idx)) {
+ rv[++count]=value.substring(last,idx);
+ last = ++idx;
+ }
+ rv[++count]=value.substring(last);
+ }
+ return rv;
+ }
+
+ public static String[] splitTrim(char c, String value) {
+ // Count items to preallocate Array (memory alloc is more expensive than counting twice)
+ int count,idx;
+ for(count=1,idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,++idx),++count);
+ String[] rv = new String[count];
+ if(count==1) {
+ rv[0]=value.trim();
+ } else {
+ int last=0;
+ count=-1;
+ for(idx=value.indexOf(c);idx>=0;idx=value.indexOf(c,idx)) {
+ rv[++count]=value.substring(last,idx).trim();
+ last = ++idx;
+ }
+ rv[++count]=value.substring(last).trim();
+ }
+ return rv;
+ }
+
+ public static String[] splitTrim(char c, String value, int size) {
+ int idx;
+ String[] rv = new String[size];
+ if(size==1) {
+ rv[0]=value.trim();
+ } else {
+ int last=0;
+ int count=-1;
+ size-=2;
+ for(idx=value.indexOf(c);idx>=0 && count<size;idx=value.indexOf(c,idx)) {
+ rv[++count]=value.substring(last,idx).trim();
+ last = ++idx;
+ }
+ rv[++count]=value.substring(last).trim();
+ }
+ return rv;
+ }
+
+}
diff --git a/env/src/main/java/com/att/inno/env/util/StringBuilderOutputStream.java b/env/src/main/java/com/att/inno/env/util/StringBuilderOutputStream.java
new file mode 100644
index 0000000..a3f8f4b
--- /dev/null
+++ b/env/src/main/java/com/att/inno/env/util/StringBuilderOutputStream.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.inno.env.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class StringBuilderOutputStream extends OutputStream {
+ private StringBuilder buf;
+
+
+ /**
+ * Create a new string writer using the default initial string-buffer
+ * size.
+ */
+ public StringBuilderOutputStream() {
+ buf = new StringBuilder();
+ }
+
+ /**
+ * Create a new string writer using a passed in StringBuilder
+ * size.
+ */
+ public StringBuilderOutputStream(StringBuilder sb) {
+ buf = sb;
+ }
+
+ /**
+ * Create a new string writer using the specified initial string-buffer
+ * size.
+ *
+ * @param initialSize
+ * The number of <tt>byte</tt> values that will fit into this buffer
+ * before it is automatically expanded
+ *
+ * @throws IllegalArgumentException
+ * If <tt>initialSize</tt> is negative
+ */
+ public StringBuilderOutputStream(int initialSize) {
+ if (initialSize < 0) {
+ throw new IllegalArgumentException("Negative buffer size");
+ }
+ buf = new StringBuilder(initialSize);
+ }
+
+ /**
+ * Write a single character.
+ */
+ public void write(int c) {
+ buf.append((byte) c);
+ }
+
+ /**
+ * Write a portion of an array of characters.
+ *
+ * @param bbuf Array of characters
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ */
+
+ public void write(byte bbuf[], int off, int len) {
+ if ((off < 0) || (off > bbuf.length) || (len < 0) ||
+ ((off + len) > bbuf.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ buf.append(new String(bbuf, off, len));
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ buf.append(new String(b));
+ }
+
+ /**
+ * Write a string.
+ */
+ public void write(String str) {
+ buf.append(str);
+ }
+
+ /**
+ * Write a portion of a string.
+ *
+ * @param str String to be written
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ */
+ public void write(String str, int off, int len) {
+ buf.append(str,off,len);
+ }
+
+ public StringBuilderOutputStream append(CharSequence csq) {
+ if (csq == null) {
+ write("null");
+ } else {
+ for(int i = 0;i<csq.length();++i) {
+ buf.append(csq.charAt(i));
+ }
+ }
+ return this;
+ }
+
+ public StringBuilderOutputStream append(CharSequence csq, int start, int end) {
+ CharSequence cs = (csq == null ? "null" : csq);
+ return append(cs.subSequence(start, end));
+ }
+
+ /**
+ * Appends the specified character to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(c) </pre>
+ *
+ * @param c
+ * The 16-bit character to append
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public StringBuilderOutputStream append(byte c) {
+ buf.append(c);
+ return this;
+ }
+
+ /**
+ * Return the buffer's current value as a string.
+ */
+ public String toString() {
+ return buf.toString();
+ }
+
+ /**
+ * Return the string buffer itself.
+ *
+ * @return StringBuffer holding the current buffer value.
+ */
+ public StringBuilder getBuffer() {
+ return buf;
+ }
+
+ public void reset() {
+ buf.setLength(0);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+}
diff --git a/env/src/main/java/com/att/inno/env/util/StringBuilderWriter.java b/env/src/main/java/com/att/inno/env/util/StringBuilderWriter.java
new file mode 100644
index 0000000..833bd7c
--- /dev/null
+++ b/env/src/main/java/com/att/inno/env/util/StringBuilderWriter.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.inno.env.util;
+
+import java.io.IOException;
+import java.io.Writer;
+
+public class StringBuilderWriter extends Writer {
+ private StringBuilder buf;
+
+
+ /**
+ * Create a new string writer using the default initial string-buffer
+ * size.
+ */
+ public StringBuilderWriter() {
+ buf = new StringBuilder();
+ }
+
+ /**
+ * Create a new string writer using a passed in StringBuilder
+ * size.
+ */
+ public StringBuilderWriter(StringBuilder sb) {
+ buf = sb;
+ }
+
+ /**
+ * Create a new string writer using the specified initial string-buffer
+ * size.
+ *
+ * @param initialSize
+ * The number of <tt>char</tt> values that will fit into this buffer
+ * before it is automatically expanded
+ *
+ * @throws IllegalArgumentException
+ * If <tt>initialSize</tt> is negative
+ */
+ public StringBuilderWriter(int initialSize) {
+ if (initialSize < 0) {
+ throw new IllegalArgumentException("Negative buffer size");
+ }
+ buf = new StringBuilder(initialSize);
+ }
+
+ /**
+ * Write a single character.
+ */
+ public void write(int c) {
+ buf.append((char) c);
+ }
+
+ /**
+ * Write a portion of an array of characters.
+ *
+ * @param cbuf Array of characters
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ */
+ public void write(char cbuf[], int off, int len) {
+ if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+ ((off + len) > cbuf.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ buf.append(cbuf, off, len);
+ }
+
+ /**
+ * Write a string.
+ */
+ public void write(String str) {
+ buf.append(str);
+ }
+
+ /**
+ * Write a portion of a string.
+ *
+ * @param str String to be written
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ */
+ public void write(String str, int off, int len) {
+ char[] chars = new char[len];
+ str.getChars(off, off+len, chars, 0);
+ buf.append(chars);
+ }
+
+ public StringBuilderWriter append(CharSequence csq) {
+ if (csq == null) {
+ write("null");
+ } else {
+ buf.append(csq);
+ }
+ return this;
+ }
+
+ public StringBuilderWriter append(CharSequence csq, int start, int end) {
+ CharSequence cs = (csq == null ? "null" : csq);
+ return append(cs.subSequence(start, end));
+ }
+
+ /**
+ * Appends the specified character to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(c) </pre>
+ *
+ * @param c
+ * The 16-bit character to append
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public StringBuilderWriter append(char c) {
+ buf.append(c);
+ return this;
+ }
+
+ /**
+ * Return the buffer's current value as a string.
+ */
+ public String toString() {
+ return buf.toString();
+ }
+
+ /**
+ * Return the string buffer itself.
+ *
+ * @return StringBuffer holding the current buffer value.
+ */
+ public StringBuilder getBuffer() {
+ return buf;
+ }
+
+ public void reset() {
+ buf.setLength(0);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+}