You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2015/04/28 23:03:32 UTC
[5/9] jena git commit: Import of lib, io,
logging and iterator packages
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/FileOps.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/FileOps.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/FileOps.java
new file mode 100644
index 0000000..6862f4a
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/FileOps.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib ;
+
+import java.io.File ;
+import java.io.FileInputStream ;
+import java.io.FileOutputStream ;
+import java.io.IOException ;
+import java.nio.channels.FileChannel ;
+
+import org.apache.jena.atlas.AtlasException ;
+import org.apache.jena.atlas.io.IO ;
+import org.apache.jena.atlas.logging.Log ;
+
+/** A library of utility operations on files and the filing system */
+public class FileOps {
+ // Update implementations as standard library functions appear that meet the contract.
+ private FileOps() {}
+
+ /**
+ * Delete a file
+ *
+ * @param filename
+ */
+ public static void delete(String filename) {
+ delete(new File(filename), true) ;
+ }
+
+ /* Delete a file - don't check it worked */
+
+ public static void deleteSilent(String filename) {
+ delete(new File(filename), false) ;
+ }
+
+ public static void delete(File f, boolean reportExistsAfter) {
+ try {
+ /*
+ * Note: On windows, deleting a file which has been memory mapped
+ * does not delete the file.
+ */
+ f.delete() ;
+ if ( reportExistsAfter && f.exists() )
+ Log.warn(FileOps.class, "delete: *** File still exists: " + f) ;
+ }
+ catch (SecurityException ex) {
+ Log.warn(FileOps.class, "delete: " + f + ": Security exception; " + ex.getMessage()) ;
+ }
+
+ }
+
+ /** Delete all files in a directory */
+ public static void clearDirectory(String dir) {
+ File d = new File(dir) ;
+ for ( File f : d.listFiles() ) {
+ if ( f.isFile() )
+ delete(f, false) ;
+ }
+ }
+
+ /** Delete all files and directories (recursively) in a directory */
+ public static void clearAll(String d) {
+ clearAll(new File(d)) ;
+ }
+
+ /** Delete all files and directories (recursively) in a directory */
+ public static void clearAll(File d) {
+ if ( ! d.exists() )
+ return ;
+
+ for ( File f : d.listFiles() ) {
+ if ( ".".equals(f.getName()) || "..".equals(f.getName()) )
+ continue ;
+ if ( f.isDirectory() )
+ clearAll(f) ;
+ f.delete() ;
+ }
+ }
+
+ /** See if there are any files in this directory */
+ public static boolean existsAnyFiles(String dir) {
+ File d = new File(dir) ;
+ File[] entries = d.listFiles() ;
+ if ( entries == null )
+ // Not a directory
+ return false ;
+ return entries.length > 0 ;
+ }
+
+ /** Test for existence */
+ public static boolean exists(String path) {
+ File f = new File(path) ;
+ return f.exists() ;
+ }
+
+ /** Test for an empty file */
+ public static boolean isEmpty(String filename) {
+ File f = new File(filename) ;
+ if ( f.exists() )
+ return true ;
+ if ( f.isFile() )
+ return f.length() == 0 ;
+ throw new AtlasException("Not a file") ;
+ }
+
+ /** Ensure a directory exists */
+ public static void ensureDir(String dirname) {
+ File dir = new File(dirname) ;
+ if ( !dir.exists() )
+ dir.mkdirs() ;
+ }
+
+ /**
+ * Split a file name into path, basename and extension. Nulls returned if
+ * don't make sense.
+ */
+ public static Tuple<String> splitDirBaseExt(String filename) {
+ String path = null ;
+ String basename = filename ;
+ String ext = null ;
+
+ int j = filename.lastIndexOf('/') ;
+ if ( j < 0 )
+ j = filename.lastIndexOf('\\') ;
+
+ if ( j >= 0 ) {
+ path = filename.substring(0, j) ;
+ basename = filename.substring(j + 1) ;
+ }
+
+ int i = basename.lastIndexOf('.') ;
+
+ if ( i > -1 ) {
+ ext = basename.substring(i + 1) ;
+ basename = basename.substring(0, i) ;
+ }
+
+ return Tuple.createTuple(path, basename, ext) ;
+ }
+
+ /**
+ * Split a file name into path and filename. Nulls returned if don't make
+ * sense.
+ */
+ public static Tuple<String> splitDirFile(String filename) {
+ String path = null ;
+ String fn = filename ;
+
+ int j = filename.lastIndexOf('/') ;
+ if ( j < 0 )
+ j = filename.lastIndexOf('\\') ;
+
+ if ( j >= 0 ) {
+ path = filename.substring(0, j) ;
+ fn = filename.substring(j + 1) ;
+ }
+ return Tuple.createTuple(path, fn) ;
+ }
+
+ /** Return the basename (no path, no extension) */
+ public static String basename(String filename) {
+ int j = filename.lastIndexOf('/') ;
+ if ( j < 0 )
+ j = filename.lastIndexOf('\\') ;
+
+ String fn = (j >= 0) ? filename.substring(j + 1) : filename ;
+ int i = fn.lastIndexOf('.') ;
+
+ if ( i > -1 )
+ return fn.substring(0, i) ;
+ return fn ;
+ }
+
+ /** Return the extension (or "") */
+ public static String extension(String filename) {
+ int iSlash = filename.lastIndexOf('/') ;
+ int iBack = filename.lastIndexOf('\\') ;
+ int iExt = filename.lastIndexOf('.') ;
+ if ( iBack > iSlash )
+ iSlash = iBack ;
+ return iExt > iSlash ? filename.substring(iExt + 1).toLowerCase() : "" ;
+ }
+
+ public static String fullPath(String filename) {
+ File f = new File(filename) ;
+ return f.getAbsolutePath() ;
+ }
+
+ public static String fullDirectoryPath(String filename) {
+ File f = new File(filename) ;
+ if ( f.isDirectory() ) {
+ return f.getAbsolutePath() ;
+ } else if ( f.getParentFile() != null ) {
+ return f.getParentFile().getAbsolutePath() ;
+ } else {
+ return f.getAbsolutePath() ;
+ }
+ }
+
+ /** Copy a file */
+ public static void copyFile(File source, File dest) {
+ try {
+ @SuppressWarnings("resource")
+ FileChannel sourceChannel = new FileInputStream(source).getChannel() ;
+ @SuppressWarnings("resource")
+ FileChannel destChannel = new FileOutputStream(dest).getChannel() ;
+ destChannel.transferFrom(sourceChannel, 0, sourceChannel.size()) ;
+ sourceChannel.close() ;
+ destChannel.close() ;
+ }
+ catch (IOException ex) {
+ IO.exception(ex) ;
+ }
+ }
+
+ // public static String getExt(String filename)
+ // {
+ // int i = filename.lastIndexOf('.') ;
+ // int j = filename.lastIndexOf('/') ;
+ // if ( i > j )
+ // return filename.substring(i+1) ;
+ // return null ;
+ // }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Hex.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Hex.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Hex.java
new file mode 100644
index 0000000..27ebbb5
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Hex.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import org.apache.jena.atlas.AtlasException ;
+
+/** Working in hex ... */
+public class Hex
+{
+ // No checking, fixed width.
+ public static int formatUnsignedLongHex(final byte[] b, final int start, final long value, final int width)
+ {
+ // Insert from low value end to high value end.
+ int idx = start+width-1 ;
+ int w = width ;
+ long x = value ;
+
+ while ( w > 0 )
+ {
+ int d = (int)(x & 0xF) ;
+ x = x>>>4 ; // Unsigned shift.
+ byte ch = Bytes.hexDigitsUC[d] ;
+ b[idx] = ch ;
+ w-- ;
+ idx-- ;
+
+ if ( x == 0 )
+ break ;
+ }
+
+ if ( x != 0 )
+ throw new AtlasException("formatUnsignedLongHex: overflow") ;
+
+ while ( w > 0 )
+ {
+ b[idx] = '0' ;
+ idx-- ;
+ w-- ;
+ }
+ return width ;
+ }
+
+ // No checking, fixed width.
+ public static long getLong(byte[] arr, int idx)
+ {
+ long x = 0 ;
+ for ( int i = 0 ; i < 16 ; i++ )
+ {
+ byte c = arr[idx] ;
+ int v = hexByteToInt(c) ;
+ x = x << 4 | v ;
+ idx++ ;
+ }
+ return x ;
+ }
+
+ public static int hexByteToInt(int c)
+ {
+ if ( '0' <= c && c <= '9' )
+ return c-'0' ;
+ else if ( 'A' <= c && c <= 'F' )
+ return c-'A'+10 ;
+ else if ( 'a' <= c && c <= 'f' )
+ return c-'a'+10 ;
+ else
+ throw new IllegalArgumentException("Bad index char : "+c) ;
+ }
+
+ /** Return the value of the hex digit, or the marker value if not a hex digit.*/
+ public static int hexByteToInt(int c, int marker)
+ {
+ if ( '0' <= c && c <= '9' )
+ return c-'0' ;
+ else if ( 'A' <= c && c <= 'F' )
+ return c-'A'+10 ;
+ else if ( 'a' <= c && c <= 'f' )
+ return c-'a'+10 ;
+ else
+ return marker ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/IRILib.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/IRILib.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/IRILib.java
new file mode 100644
index 0000000..daafb74
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/IRILib.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.io.File ;
+import java.io.IOException ;
+
+import org.apache.jena.atlas.AtlasException ;
+import org.apache.jena.base.Sys ;
+
+/** Operations related to IRIs */
+public class IRILib
+{
+ // http://www.w3.org/TR/xpath-functions/#func-encode-for-uri
+ // Encodes delimiters.
+
+ /* RFC 3986
+ *
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ / "*" / "+" / "," / ";" / "="
+ */
+
+ private static char uri_reserved[] =
+ { '!', '*', '"', '\'', '(', ')', ';', ':', '@', '&',
+ '=', '+', '$', ',', '/', '?', '%', '#', '[', ']' } ;
+
+ // No allowed in URIs
+ private static char uri_non_chars[] = { '<', '>', '{', '}', '|', '\\', '`', '^', ' ', '\n', '\r', '\t', '£' } ;
+
+ // RFC 2396
+ //private static char uri_unwise[] = { '{' , '}', '|', '\\', '^', '[', ']', '`' } ;
+
+
+ private static char[] charsComponent =
+ // reserved, + non-chars + nasties.
+ { '!', '*', '"', '\'', '(', ')', ';', ':', '@', '&',
+ '=', '+', '$', ',', '/', '?', '%', '#', '[', ']',
+ '{', '}', '|', '\\', '`', '^',
+ ' ', '<', '>', '\n', '\r', '\t', '£' } ;
+
+ private static char[] charsFilename =
+ // reserved, + non-chars + nasties.
+ // Leave : (Windows drive charcater) and / (separator) alone
+ // include SPC.
+ // Should this include "~"?
+ { '!', '*', '"', '\'', '(', ')', ';', /*':',*/ '@', '&',
+ '=', '+', '$', ',', /*'/',*/ '?', '%', '#', '[', ']',
+ '{', '}', '|', '\\', '`', '^',
+ ' ', '<', '>', '\n', '\r', '\t'} ;
+
+ private static char[] charsPath =
+ { // Reserved except leave the separators alone.
+ '!', '*', '"', '\'', '(', ')', ';', /*':',*/ '@', '&',
+ '=', '+', '$', ',', /*'/',*/ '?', '%', '#', '[', ']',
+ '{', '}', '|', '\\', '`', '^',
+ // Other junk
+ ' ', '<', '>', '\n', '\r', '\t' } ;
+
+ // The initializers must have run.
+ static final String cwd ;
+ static final String cwdURL ;
+
+ // Current directory, with trailing "/"
+ // This matters for resolution.
+ static {
+ String x = new File(".").getAbsolutePath() ;
+ x = x.substring(0, x.length()-1) ;
+ cwd = x ;
+ cwdURL = plainFilenameToURL(cwd) ;
+ }
+
+ // See also IRIResolver
+ /** Return a string that is an IRI for the filename.*/
+ public static String fileToIRI(File f) {
+ return filenameToIRI(f.getAbsolutePath()) ;
+ }
+
+ /** Create a string that is a IRI for the filename.
+ * <li>The file name may already have {@code file:}.
+ * <li>The file name may be relative.
+ * <li>Encode using the rules for a path (e.g. ':' and'/' do not get encoded)
+ * <li>Non-IRI characters get %-encoded.
+ */
+ public static String filenameToIRI(String fn) {
+ if ( fn == null ) return cwdURL ;
+
+ if ( fn.length() == 0 ) return cwdURL ;
+
+ if ( fn.startsWith("file:") )
+ return normalizeFilenameURI(fn) ;
+ return plainFilenameToURL(fn) ;
+ }
+
+ /** Convert a file: IRI to a filename */
+ public static String IRIToFilename(String iri) {
+ if ( ! iri.startsWith("file:") )
+ throw new AtlasException("Not a file: URI: "+iri) ;
+
+ String fn ;
+ if ( iri.startsWith("file:///") )
+ fn = iri.substring("file://".length()) ;
+ else
+ fn = iri.substring("file:".length()) ;
+ return decode(fn) ;
+ }
+
+ /** Convert a plain file name (no file:) to a file: URL */
+ private static String plainFilenameToURL(String fn) {
+ // No "file:"
+ // Make Absolute filename.
+ boolean trailingSlash = fn.endsWith("/") ;
+ File file = new File(fn) ;
+
+ try { fn = file.getCanonicalPath() ; }
+ catch (IOException e) { fn = file.getAbsolutePath() ; }
+
+ if ( trailingSlash && ! fn.endsWith("/") )
+ fn = fn + "/" ;
+
+ if ( Sys.isWindows )
+ {
+ // C:\ => file:///C:/...
+ if ( fn.length() >= 2 && fn.charAt(1) == ':' )
+ // Windows drive letter - already absolute path.
+ // Make "URI" absolute path
+ fn = "/"+fn ;
+ // Convert \ to /
+ // Maybe should do this on all platforms? i.e consistency.
+ fn = fn.replace('\\', '/' ) ;
+ }
+
+ fn = encodeFileURL(fn) ;
+ return "file://"+fn ;
+ }
+
+
+ /** Sanitize a "file:" URL. Must start "file:" */
+ private static String normalizeFilenameURI(String fn) {
+ if ( ! fn.startsWith("file:/") )
+ {
+ // Relative path.
+ String fn2 = fn.substring("file:".length()) ;
+ return plainFilenameToURL(fn2) ;
+ }
+
+ // Starts file:///
+ if ( fn.startsWith("file:///") )
+ // Assume it's good and return as-is.
+ return fn ;
+
+ if ( fn.startsWith("file://") )
+ {
+ String fn2 = fn.substring("file:/".length()) ; // Leave one "/"
+ return plainFilenameToURL(fn2) ;
+ }
+
+ // Must be file:/
+ String fn2 = fn.substring("file:".length()) ;
+ return plainFilenameToURL(fn2) ;
+ }
+
+ /** Encode using the rules for a component (e.g. ':' and '/' get encoded)
+ * Does not encode non-ASCII characters
+ */
+ public static String encodeUriComponent(String string) {
+ String encStr = StrUtils.encodeHex(string,'%', charsComponent) ;
+ return encStr ;
+ }
+
+ /** Encode using the rules for a file: URL.
+ * Does not encode non-ASCII characters
+ */
+ public static String encodeFileURL(String string) {
+ String encStr = StrUtils.encodeHex(string,'%', charsFilename) ;
+ return encStr ;
+ }
+
+ /** Encode using the rules for a path (e.g. ':' and '/' do not get encoded) */
+ public static String encodeUriPath(String uri) {
+ // Not perfect.
+ // Encode path.
+ // %-encode chars.
+ uri = StrUtils.encodeHex(uri, '%', charsPath) ;
+ return uri ;
+ }
+
+ public static String decode(String string) {
+ return StrUtils.decodeHex(string, '%') ;
+ }
+
+ public static String encodeNonASCII(String string) {
+ if ( ! containsNonASCII(string) )
+ return string ;
+
+ byte[] bytes = StrUtils.asUTF8bytes(string) ;
+ StringBuilder sw = new StringBuilder() ;
+ for ( byte b : bytes )
+ {
+ // Signed bytes ...
+ if ( b > 0 )
+ {
+ sw.append( (char) b );
+ continue;
+ }
+
+ int hi = ( b & 0xF0 ) >> 4;
+ int lo = b & 0xF;
+ sw.append( '%' );
+ sw.append( Chars.hexDigitsUC[hi] );
+ sw.append( Chars.hexDigitsUC[lo] );
+ }
+ return sw.toString() ;
+ }
+
+ public static boolean containsNonASCII(String string){
+ boolean clean = true ;
+ for ( int i = 0 ; i < string.length() ; i++ )
+ {
+ char ch = string.charAt(i) ;
+ if ( ch >= 127 )
+ return true;
+ }
+ return false ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/InternalErrorException.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/InternalErrorException.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/InternalErrorException.java
new file mode 100644
index 0000000..b20b2d6
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/InternalErrorException.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+public class InternalErrorException extends RuntimeException
+{
+ public InternalErrorException() { super() ; }
+ public InternalErrorException(String msg) { super(msg) ; }
+ public InternalErrorException(Throwable th) { super(th) ; }
+ public InternalErrorException(String msg, Throwable th) { super(msg, th) ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Lib.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Lib.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Lib.java
new file mode 100644
index 0000000..6c9c442
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Lib.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.List ;
+import java.util.zip.Adler32 ;
+import java.util.zip.CRC32 ;
+import java.util.zip.Checksum ;
+
+import org.apache.jena.atlas.logging.Log ;
+
+public class Lib
+{
+ private Lib() {}
+
+ public static final void sync(Object object)
+ {
+ if ( object instanceof Sync )
+ ((Sync)object).sync() ;
+ }
+
+ /** Return true if obj1 and obj are both null or are .equals, else return false */
+ public static final <T> boolean equal(T obj1, T obj2)
+ {
+ if ( obj1 == null )
+ return obj2 == null ;
+ // obj1 != null
+ if ( obj2 == null )
+ return false ;
+ return obj1.equals(obj2) ;
+ }
+
+ /** Return true if obj1 and obj are both null or are .equals, else return false */
+ public static final boolean equalsIgnoreCase(String str1, String str2)
+ {
+ if ( str1 == null )
+ return str2 == null ;
+ return str1.equalsIgnoreCase(str2) ;
+ }
+
+
+ /** Return true if obj1 and obj are ! equal */
+ public static final <T> boolean notEqual(T obj1, T obj2)
+ {
+ return ! equal(obj1, obj2) ;
+ }
+
+ /** Safely return the class short name for an object -- obj.getClass().getSimpleName() */
+ static public final String className(Object obj) {
+ if ( obj == null )
+ return "null" ;
+ return classShortName(obj.getClass()) ;
+ }
+
+ /** Safely return the class short name for a class */
+ static public final String classShortName(Class<? > cls) {
+ if ( cls == null )
+ return "null" ;
+ return cls.getSimpleName() ;
+ }
+
+ /** Do two lists have the same elements? */
+ public static <T> boolean equalsListAsSet(List<T> list1, List<T> list2) {
+ if ( list1 == null && list2 == null )
+ return true ;
+ if ( list1 == null ) return false ;
+ if ( list2 == null ) return false ;
+ return list1.containsAll(list2) && list2.containsAll(list1) ;
+ }
+
+ /** HashCode - allow nulls */
+ public static final int hashCodeObject(Object obj) { return hashCodeObject(obj, -4) ; }
+
+ /** HashCode - allow nulls */
+ public static final int hashCodeObject(Object obj, int nullHashCode)
+ {
+ if ( obj == null )
+ return nullHashCode ;
+ return obj.hashCode() ;
+ }
+
+ public static final void sleep(int milliSeconds)
+ {
+ try { Thread.sleep(milliSeconds) ; }
+ catch (InterruptedException ex) { Log.warn(Lib.class, "interrupted", ex) ; }
+ }
+
+ /**
+ * @see CRC32
+ */
+ public static long crc32(byte[] bytes)
+ {
+ return crc(new CRC32(), bytes) ;
+ }
+
+ /** Faster than CRC32, nearly as good.
+ * @see Adler32
+ */
+ public static long adler32(byte[] bytes)
+ {
+ return crc(new Adler32(), bytes) ;
+ }
+
+ private static long crc(Checksum alg, byte[] bytes)
+ {
+ alg.reset() ;
+ alg.update(bytes, 0, bytes.length) ;
+ return alg.getValue() ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/ListUtils.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/ListUtils.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/ListUtils.java
new file mode 100644
index 0000000..78d591a
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/ListUtils.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.ArrayList ;
+import java.util.List ;
+
+
+import org.apache.jena.atlas.io.IndentedWriter ;
+import org.apache.jena.atlas.iterator.Action ;
+import org.apache.jena.atlas.iterator.FilterUnique ;
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.logging.Log ;
+
+/** Various things for lists */
+public class ListUtils
+{
+ private ListUtils() {}
+
+ public static <T>
+ List<T> unique(List<T> list)
+ {
+ Iter<T> iter = Iter.iter(list.iterator()) ;
+ return iter.filter(new FilterUnique<T>()).toList() ;
+ }
+
+ public static
+ List<Integer> asList(int... values)
+ {
+ List<Integer> x = new ArrayList<>() ;
+ for ( int v : values )
+ x.add(v) ;
+ return x ;
+ }
+
+ public static <T> String str(T[] array)
+ {
+ StringBuilder buff = new StringBuilder() ;
+ String sep = "[" ;
+
+ for ( T anArray : array )
+ {
+ buff.append( sep );
+ sep = ", ";
+ buff.append( anArray );
+ }
+ buff.append("]") ;
+ return buff.toString() ;
+ }
+
+ public static String str(int[] array)
+ {
+ StringBuilder buff = new StringBuilder() ;
+ String sep = "[" ;
+
+ for ( int anArray : array )
+ {
+ buff.append( sep );
+ sep = ", ";
+ buff.append( anArray );
+ }
+ buff.append("]") ;
+ return buff.toString() ;
+ }
+
+ public static String str(long[] array)
+ {
+ StringBuilder buff = new StringBuilder() ;
+ String sep = "[" ;
+
+ for ( long anArray : array )
+ {
+ buff.append( sep );
+ sep = ", ";
+ buff.append( anArray );
+ }
+ buff.append("]") ;
+ return buff.toString() ;
+ }
+
+ public static <T> void print(IndentedWriter out, List<T> list)
+ {
+ print(out, list, " ") ;
+ }
+
+ public static <T> void print(final IndentedWriter out, List<T> list, final String sep)
+ {
+ Action<T> output = new Action<T>() {
+ boolean first = true ;
+ @Override
+ public void apply(T item)
+ {
+ if ( ! first ) out.print(sep) ;
+ out.print(item.toString()) ;
+ first = false ;
+ }
+ } ;
+ Iter.apply(list.iterator(), output) ;
+ }
+
+ /** Return a list of lists of all the elements of collection in every order
+ * Easy to run out of heap memory.
+ */
+ static public <T> List<List<T>> permute(List<T> c)
+ {
+ if ( c.size() > 5 )
+ {
+ Log.warn(ListUtils.class, "Attempt to permute more than 5 items - think again") ;
+ return null ;
+ }
+
+ List<List<T>> x = new ArrayList<>() ;
+ if ( c.size() == 1 )
+ {
+ x.add(c) ;
+ return x ;
+ }
+
+ for ( T obj : c )
+ {
+ List<T> c2 = new ArrayList<>(c) ;
+ c2.remove(obj) ;
+ List<List<T>> x2 = permute(c2) ;
+ // For each list returned
+ for ( List<T> x3 : x2 )
+ {
+ // Gives a more expected ordering
+ x3.add(0,obj) ;
+ x.add(x3) ;
+ }
+ }
+ return x ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Map2.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Map2.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Map2.java
new file mode 100644
index 0000000..75697e0
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Map2.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+
+import java.util.Iterator ;
+import java.util.Map ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+
+
+/**
+ * A map with parent sharing. New entries go into a map but lookup is passed to
+ * the parent map if nothing is found at this level.
+ */
+public class Map2<K, V> implements Iterable<K>
+{
+ private final Map<K, V> map1 ;
+ private final Map2<K, V> map2 ;
+
+ public Map2(Map<K,V> map1, Map2<K,V> map2)
+ {
+ this.map1 = map1 ;
+ this.map2 = map2 ;
+ }
+
+ public boolean containsKey(K key)
+ {
+ if ( map1.containsKey(key) )
+ return true ;
+ if ( map2 != null )
+ return map2.containsKey(key) ;
+ return false;
+ }
+
+// public boolean containsValue(V value)
+// {
+// if ( map1.containsValue(value) )
+// return true ;
+// if ( map2 != null )
+// return map2.containsValue(value) ;
+// return false;
+// }
+
+ public V get(K key)
+ {
+ V v = map1.get(key) ;
+ if ( v != null ) return v ;
+ if ( map2 != null )
+ return map2.get(key) ;
+ return null ;
+ }
+
+ public void put(K key, V value)
+ {
+ if ( map2 != null && map2.containsKey(key) )
+ throw new IllegalArgumentException("Parent map already contains "+key) ;
+ map1.put(key, value) ;
+ }
+
+ // The keys.
+ @Override
+ public Iterator<K> iterator()
+ {
+ Iter<K> iter1 = Iter.iter(map1.keySet().iterator()) ;
+ if ( map2 == null )
+ return iter1 ;
+ return iter1.append(map2.iterator()) ;
+ }
+
+ public boolean isEmpty()
+ {
+ boolean x = map1.isEmpty() ;
+ if ( ! x ) return false ;
+ if ( map2 != null )
+ return map2.isEmpty() ;
+ return true ;
+ }
+
+ public int size()
+ {
+ int x = map1.size() ;
+ if ( map2 != null )
+ x += map2.size();
+ return x ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/MapUtils.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/MapUtils.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/MapUtils.java
new file mode 100644
index 0000000..7999a25
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/MapUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.Map ;
+
+/** Map specific functions */
+public class MapUtils
+{
+ private MapUtils() {}
+
+ public static <K, V> void apply(Map<K, V> map, ActionKeyValue<K, V> action)
+ {
+ for ( Map.Entry<K,V> entry : map.entrySet() )
+ action.apply(entry.getKey(), entry.getValue()) ;
+ }
+
+ public static <T> void increment(Map<T, Integer> countMap, T key)
+ { increment(countMap, key, 1) ; }
+
+ public static <T> void increment(Map<T, Integer> countMap, T key, int incr)
+ {
+ Integer integer = countMap.get(key) ;
+ if ( integer == null )
+ countMap.put(key, incr) ;
+ else
+ countMap.put(key, integer+incr) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMap.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMap.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMap.java
new file mode 100644
index 0000000..2782ea6
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMap.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.* ;
+
+import org.apache.jena.atlas.iterator.IteratorConcat ;
+
+/* Map from K to collection of V */
+
+public abstract class MultiMap<K, V>
+{
+ private Map<K, Collection<V>> map = new HashMap<>() ;
+
+ protected abstract Collection<V> createCollection() ;
+
+ public static <K, V> MultiMapToList<K, V> createMapList() { return new MultiMapToList<>() ; }
+ public static <K, V> MultiMapToSet<K, V> createMapSet() { return new MultiMapToSet<>() ; }
+
+ protected MultiMap() { }
+
+ protected Collection<V> getByKey(K key) {
+ return map.get(key) ;
+ }
+
+ public abstract Collection<V> get(K key) ;
+
+ public V getOne(K key) {
+ Collection<V> c = map.get(key) ;
+ if ( c == null || c.size() == 0 )
+ return null ;
+ return c.iterator().next() ;
+ }
+
+ public void putAll(K key, @SuppressWarnings("unchecked") V ... values)
+ {
+ for ( V v : values)
+ put(key, v) ;
+ }
+
+ public void put(K key, V value)
+ {
+ Collection<V> x = map.get(key) ;
+ if ( x == null )
+ {
+ x = createCollection() ;
+ map.put(key, x) ;
+ }
+ x.add(value) ;
+ }
+
+ public void remove(K key, V value) {
+ if ( map.containsKey(key))
+ map.get(key).remove(value) ;
+ }
+ public void removeKey(K key) { map.remove(key) ; }
+
+ protected Collection<V> valuesForKey(K key) { return map.get(key); }
+ public abstract Collection<V> values(K key) ;
+ public abstract Collection<V> values() ;
+
+ public boolean containsKey(K key) { return map.containsKey(key) ; }
+
+ public Set<K> keys() { return map.keySet() ; }
+
+ public void clear() { map.clear() ; }
+
+ public boolean isEmpty() { return map.isEmpty() ; }
+
+ /** Does not materialise the contents */
+ public Iterator<V> flatten()
+ {
+ IteratorConcat<V> all = new IteratorConcat<>() ;
+ for ( K k : map.keySet() )
+ {
+ Collection<V> x = map.get(k) ;
+ all.add(x.iterator()) ;
+ }
+ return all ;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if ( this == obj )
+ return true ;
+ if ( obj == null )
+ return false ;
+ if ( getClass() != obj.getClass() )
+ return false ;
+ MultiMap<?,?> other = (MultiMap<?,?>)obj ;
+ if ( map == null ) {
+ if ( other.map != null )
+ return false ;
+ } else if ( !map.equals(other.map) )
+ return false ;
+ return true ;
+ }
+
+ @Override
+ public int hashCode() { return map.hashCode()^ 0x01010101 ; }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder() ;
+ sb.append("{ ") ;
+ boolean firstKey = true ;
+ for ( K key : keys() )
+ {
+ if ( ! firstKey )
+ sb.append(", ") ;
+ firstKey = false ;
+ sb.append(key) ;
+ sb.append(" => [") ;
+ boolean firstValue = true ;
+ for ( V value : values(key) )
+ {
+ if ( firstValue )
+ sb.append(" ") ;
+ else
+ sb.append(", ") ;
+ sb.append(value) ;
+ firstValue = false ;
+ }
+ sb.append(" ] ") ;
+ }
+ sb.append("}") ;
+ return sb.toString() ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMapToList.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMapToList.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMapToList.java
new file mode 100644
index 0000000..ac1ba70
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMapToList.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.ArrayList ;
+import java.util.Collection ;
+import java.util.List ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+
+public class MultiMapToList<K,V> extends MultiMap<K,V> {
+ public static <K, V> MultiMapToList<K, V> create() { return new MultiMapToList<>() ; }
+
+ @Override
+ protected Collection<V> createCollection() {
+ return new ArrayList<>() ;
+ }
+
+ @Override
+ public List<V> get(K key) { return (List<V>)getByKey(key); }
+
+ @Override
+ public List<V> values(K key) { return (List<V>)valuesForKey(key); }
+
+ @Override
+ public List<V> values() { return Iter.toList(flatten()) ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMapToSet.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMapToSet.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMapToSet.java
new file mode 100644
index 0000000..b89e05b
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiMapToSet.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.Collection ;
+import java.util.HashSet ;
+import java.util.Set ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+
+public class MultiMapToSet<K,V> extends MultiMap<K,V> {
+ public static <K, V> MultiMapToSet<K, V> create() { return new MultiMapToSet<>() ; }
+
+ @Override
+ protected Collection<V> createCollection()
+ {
+ return new HashSet<>() ;
+ }
+
+ @Override
+ public Set<V> get(K key) { return (Set<V>)getByKey(key) ; }
+
+ @Override
+ public Set<V> values(K key) { return (Set<V>)valuesForKey(key); }
+
+ @Override
+ public Set<V> values() { return Iter.toSet(flatten()) ; }
+
+
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiSet.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiSet.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiSet.java
new file mode 100644
index 0000000..3701042
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/MultiSet.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.ArrayList ;
+import java.util.HashMap ;
+import java.util.Iterator ;
+import java.util.List ;
+import java.util.Map ;
+import java.util.NoSuchElementException ;
+
+/** A MultiSet - also known as a Bag
+ */
+
+public class MultiSet<T> implements Iterable<T>
+{
+ private Map<T,RefLong> map = new HashMap<>() ;
+ private int multiSetSize = 0 ;
+
+ private RefLong _get(T obj)
+ {
+ RefLong z = map.get(obj) ;
+ if ( z == null )
+ {
+ z = new RefLong(0) ;
+ map.put(obj, z) ;
+ }
+ return z ;
+ }
+
+ /** Does it contain any elements at all? */
+ public boolean isEmpty() { return map.isEmpty() ; }
+
+ /** Does it contain the object? */
+ public boolean contains(T obj) { return map.containsKey(obj) ; }
+
+ /** Yield one object per element (i.e without counts) */
+ public Iterator<T> elements() { return map.keySet().iterator() ; }
+
+ /** Add an object */
+ public void add(T obj) { _get(obj).inc(); multiSetSize++ ; }
+
+ /** Add an object, with cardinality n */
+ public void add(T obj, long n)
+ {
+ if ( n <= 0 ) return ;
+ _get(obj).add(n) ;
+ multiSetSize += n ;
+ }
+
+ /** Remove one occurrence of the object from the multiset */
+ public void remove(T obj)
+ {
+ RefLong x = map.get(obj) ;
+ if ( x == null ) return ;
+ x.dec() ;
+ multiSetSize-- ;
+ if ( x.value() == 0 )
+ map.remove(obj) ;
+ }
+
+ /** Remove N occurrences of the object from the multiset */
+ public void remove(T obj, long n)
+ {
+ RefLong x = map.get(obj) ;
+ if ( x == null ) return ;
+ long z = x.value() ;
+ if ( z < n )
+ n = z ;
+ x.subtract(n) ;
+ multiSetSize -= n ;
+ if ( x.value() <= 0 )
+ map.remove(obj) ;
+ }
+
+
+ /** Remove all occurrences of the object in themultiset */
+ public void removeAll(T obj)
+ {
+ RefLong x = map.get(obj) ;
+ if ( x == null )
+ return ;
+ multiSetSize -= x.value() ;
+ map.remove(obj) ;
+ }
+
+ /* Remove everything */
+ public void clear() { map.clear() ; multiSetSize = 0 ; }
+
+
+ /** Get the count of the number of times the object appears in the multiset - i.e. it's cardinality.
+ * Returns zero when not present.
+ */
+ public long count(T obj)
+ {
+ if ( ! map.containsKey(obj) ) return 0 ;
+ return map.get(obj).value() ;
+ }
+
+ public int size()
+ {
+// int count = 0 ;
+// for ( Map.Entry<T, RefLong> e : map.entrySet() )
+// count += e.getValue().value() ;
+// //return count ;
+// if ( count != multiSetSize )
+// {
+// Log.warn(this, "Mismatch") ;
+// return count ;
+// }
+
+ return multiSetSize ;
+ }
+
+ private Iterator<T> iterator1()
+ {
+ // CRUDE
+ List<T> expanded = new ArrayList<>() ;
+ for ( Map.Entry<T, RefLong> e : map.entrySet() )
+ {
+ for ( int i = 0 ; i < e.getValue().value() ; i++ )
+ expanded.add(e.getKey()) ;
+ }
+
+ return expanded.iterator() ;
+ }
+
+ @Override
+ public Iterator<T> iterator()
+ {
+ return new Iterator<T>() {
+
+ Iterator<T> keys = map.keySet().iterator() ;
+ T key = null ;
+ long keyCount = 0 ;
+ T slot = null ;
+
+ @Override
+ public boolean hasNext()
+ {
+ if ( slot != null )
+ return true ;
+
+ if ( keys == null )
+ return false ;
+
+ if ( key != null )
+ {
+ if ( keyCount < count(key) )
+ {
+ keyCount++ ;
+ slot = key ;
+ return true ;
+ }
+ // End of this key.
+ key = null ;
+ }
+
+ if ( keys.hasNext() )
+ {
+ key = keys.next() ;
+ keyCount = 1 ;
+ slot = key ;
+ return true ;
+ }
+ keys = null ;
+ return false ;
+ }
+
+ @Override
+ public T next()
+ {
+ if ( ! hasNext() ) throw new NoSuchElementException() ;
+ T x = slot ;
+ slot = null ;
+ return x ;
+ }
+
+ @Override
+ public void remove()
+ { throw new UnsupportedOperationException() ; }
+ } ;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder() ;
+ sb.append("{") ;
+ String sep = "" ;
+ for ( Map.Entry<T, RefLong> e : map.entrySet() )
+ {
+ sb.append(sep) ;
+ sep = ", " ;
+ sb.append(e.getKey().toString()) ;
+ sb.append("=") ;
+ sb.append(Long.toString(e.getValue().value())) ;
+ }
+ sb.append("}") ;
+ return sb.toString() ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/NotImplemented.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/NotImplemented.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/NotImplemented.java
new file mode 100644
index 0000000..b7e91f1
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/NotImplemented.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+public class NotImplemented extends InternalErrorException
+{
+ public NotImplemented() { super() ; }
+ public NotImplemented(String msg) { super(msg) ; }
+ public NotImplemented(Throwable th) { super(th) ; }
+ public NotImplemented(String msg, Throwable th) { super(msg, th) ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/NumberUtils.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/NumberUtils.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/NumberUtils.java
new file mode 100644
index 0000000..4f51beb
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/NumberUtils.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import org.apache.jena.atlas.AtlasException ;
+
+public class NumberUtils
+{
+ // Maximum length of a length 1,2,3,4...
+ private final static int [] maxTable = {
+ 9, 99, 999, 9999, 99999, 999999, 9999999,
+ 99999999, 999999999, Integer.MAX_VALUE };
+
+ /** Fast, but basic, integer to StringBuilder */
+ public static void formatInt(StringBuilder sb, int value)
+ {
+ // SeeAlso Integer.toString.
+ int len = length(value) ;
+ formatInt(sb, value, len, false) ;
+ }
+
+ /** Fast, but basic, integer to StringBuilder : always signed */
+ public static void formatSignedInt(StringBuilder sb, int value)
+ {
+ int len = length(value) ;
+ if ( value >= 0 )
+ len++ ;
+ formatInt(sb, value, len, true) ;
+ }
+
+ static int length(int x)
+ {
+ if ( x < 0 )
+ return length(-x)+1 ;
+
+ for (int i=0; ; i++)
+ if (x <= maxTable[i])
+ return i+1;
+ }
+
+ /** Place a fixed width representation of a non-negative int into the string buffer */
+ public static void formatInt(StringBuilder sb, int value, int width)
+ {
+ formatInt(sb, value, width, false) ;
+ }
+
+ /** Place a fixed width representation into the string buffer : always signed. */
+ public static void formatSignedInt(StringBuilder sb, int value, int width)
+ {
+ formatInt(sb, value, width, true) ;
+ }
+
+ /** Format an integer, which may be signed */
+ public static void formatInt(StringBuilder sb, int value, int width, boolean signAlways)
+ {
+ boolean negative = (value < 0 ) ;
+
+ if ( negative )
+ {
+ value = -value ;
+ width -- ;
+ sb.append('-') ;
+ }
+ else if ( signAlways )
+ {
+ width -- ;
+ sb.append('+') ;
+ }
+
+ formatUnsignedInt(sb, value, width) ;
+ }
+
+ /** Place a fixed width representation into the string buffer : never signed. */
+ public static void formatUnsignedInt(StringBuilder sb, int value, int width)
+ {
+ char chars[] = new char[width] ;
+ formatUnsignedInt$(chars, value, width) ;
+
+ // Append - the buffer was filled backwards.
+ for ( int i = 0 ; i < width ; i++ )
+ // Un-backwards.
+ sb.append(chars[width-1-i]) ;
+
+ }
+
+ // No checking. char[] filled backwards
+ private static int formatUnsignedInt$(char[] b, int x, int width)
+ {
+ // x >= 0
+ // Inserts chars backwards
+ int idx = 0 ;
+ while ( width > 0 )
+ {
+ int i = x%10 ;
+ char ch = Chars.digits10[i] ;
+ b[idx] = ch ;
+ width-- ;
+ idx++ ;
+
+ x = x / 10 ;
+ if ( x == 0 )
+ break ;
+ }
+
+ if ( x != 0 )
+ throw new AtlasException("formatInt: overflow[x="+x+", width="+width+"]") ;
+
+ while ( width > 0 )
+ {
+ b[idx] = '0' ;
+ idx++ ;
+ width-- ;
+ }
+ return width ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Pair.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Pair.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Pair.java
new file mode 100644
index 0000000..4f3b055
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Pair.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import static org.apache.jena.atlas.lib.Lib.hashCodeObject ;
+import static org.apache.jena.atlas.lib.StrUtils.str ;
+
+public class Pair<A, B>
+{
+ public static <L, R> Pair<L,R> create(L x, R y) { return new Pair<>(x,y) ; }
+
+ final A a ;
+ final B b ;
+ public Pair(A a, B b) { this.a = a; this.b = b ; }
+
+ public A getLeft() { return a ; }
+ public B getRight() { return b ; }
+
+ public A car() { return a ; }
+ public B cdr() { return b ; }
+
+ @Override
+ public int hashCode()
+ {
+ return hashCodeObject(car()) ^ hashCodeObject(cdr())<<1 ;
+ }
+
+ @Override
+ public boolean equals(Object other)
+ {
+ if ( this == other ) return true ;
+
+ // If it's a pair of a different <A,B> then .equals
+ // Pair<A,B>(null,null) is equal to Pair<C,D>(null ,null)
+ // Type erasure makes this hard to check otherwise.
+ // Use class X extends Pair<A,B> and implement .equals to do
+ // instanceof then call super.equals.
+
+ if( ! ( other instanceof Pair<?,?> ) ) return false ;
+ Pair<?,?> p2 = (Pair<?,?>)other ;
+ return Lib.equal(car(), p2.car()) && Lib.equal(cdr(), p2.cdr()) ;
+ }
+
+ @Override
+ public String toString() { return "("+str(a)+", "+str(b)+")" ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Pool.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Pool.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Pool.java
new file mode 100644
index 0000000..f28939e
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Pool.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib ;
+
+public interface Pool<T>
+{
+ public abstract void put(T item) ;
+
+ /** Get an item from the pool - return null if the pool is empty */
+ public abstract T get() ;
+
+ public abstract boolean isEmpty() ;
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/PoolBase.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/PoolBase.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/PoolBase.java
new file mode 100644
index 0000000..c6cb505
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/PoolBase.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.ArrayDeque ;
+
+/** A Pool of objects. Base implements a non-blocking pool (returns null on no entry)
+ * with infinite upper bound. Set effective size by creating the right number of
+ * entries when created.
+ */
+public class PoolBase<T> implements Pool<T>
+{
+ // For convenience we operate a LIFO policy.
+ // This not part of the extenal contract of a "pool"
+
+ ArrayDeque<T> pool = new ArrayDeque<>();
+ int maxSize = -1 ; // Unbounded
+
+ public PoolBase() {}
+ //public Pool(int maxSize) { this.maxSize = maxSize ; }
+
+ @Override
+ public void put(T item)
+ {
+ // Currently, unbounded
+ if ( maxSize >= 0 && pool.size() == 0 )
+ {}
+ pool.push(item) ;
+ }
+
+ /** Get an item from the pool - return null if the pool is empty */
+ @Override
+ public T get()
+ {
+ if ( pool.size() == 0 ) return null ;
+ return pool.pop();
+ }
+
+ @Override
+ public boolean isEmpty() { return pool.size() == 0 ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/PoolSync.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/PoolSync.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/PoolSync.java
new file mode 100644
index 0000000..10e0a6a
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/PoolSync.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+
+/** Synchronization wrapper for a pool */
+public class PoolSync<T> implements Pool<T>
+{
+ private Pool<T> pool ;
+
+ public static <T> Pool<T> create(Pool<T> pool)
+ {
+ if ( pool instanceof PoolSync<?>)
+ {
+ PoolSync<T> p = (PoolSync<T>)pool ;
+ return p ;
+ }
+ return new PoolSync<>(pool) ;
+ }
+
+ public PoolSync(Pool<T> pool) { this.pool = pool ; }
+
+ @Override
+ public final synchronized void put(T item)
+ {
+ pool.put(item) ;
+ }
+
+ @Override
+ public final synchronized T get()
+ {
+ return pool.get();
+ }
+
+ @Override
+ public final synchronized boolean isEmpty() { return pool.isEmpty() ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Problem.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Problem.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Problem.java
new file mode 100644
index 0000000..d571fe7
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Problem.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+public class Problem extends RuntimeException
+{
+ public Problem(String msg) { super(msg) ; }
+ public Problem(String msg, Throwable th) { super(msg, th) ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/PropertiesSorted.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/PropertiesSorted.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/PropertiesSorted.java
new file mode 100644
index 0000000..75060ee
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/PropertiesSorted.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.ArrayList ;
+import java.util.Collections ;
+import java.util.Comparator ;
+import java.util.Enumeration ;
+import java.util.Iterator ;
+import java.util.List ;
+import java.util.Properties ;
+
+/** Sorted output */
+public class PropertiesSorted extends Properties
+{
+ private Comparator<String> comparator = null ;
+
+ //public SortedProperties() { super() ; }
+
+ public PropertiesSorted(Comparator<String> comparator)
+ {
+ super() ;
+ this.comparator = comparator ;
+ }
+
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Override
+ public synchronized Enumeration<Object> keys()
+ {
+ // Old world - enumeration, untyped. But we know they are strings (Propetries hides non-strings in get)
+ Enumeration<Object> keys = super.keys() ;
+ List<String> keys2 = new ArrayList<>(super.size()) ;
+
+ for( ; keys.hasMoreElements() ; )
+ {
+ Object obj = keys.nextElement() ;
+ if ( obj instanceof String )
+ keys2.add((String)obj);
+ }
+ // Keys are comparable because they are strings.
+ if ( comparator == null )
+ Collections.sort(keys2);
+ else
+ Collections.sort(keys2, comparator) ;
+
+ return new IteratorToEnumeration(keys2.listIterator()) ;
+ }
+
+ static class IteratorToEnumeration<T> implements Enumeration<T>
+ {
+ private Iterator<T> iterator ;
+
+ public IteratorToEnumeration(Iterator<T> iterator)
+ {
+ this.iterator = iterator ;
+ }
+
+ @Override
+ public boolean hasMoreElements()
+ {
+ return iterator.hasNext() ;
+ }
+
+ @Override
+ public T nextElement()
+ {
+ return iterator.next();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/PropertyUtils.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/PropertyUtils.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/PropertyUtils.java
new file mode 100644
index 0000000..d4ac5b7
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/PropertyUtils.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.jena.atlas.lib ;
+
+import java.io.* ;
+import java.util.Objects ;
+import java.util.Properties ;
+
+import org.apache.jena.atlas.AtlasException ;
+import org.apache.jena.atlas.io.IO ;
+
+public class PropertyUtils {
+ /** Load properties from a file if the file exists */
+ static public Properties loadFromFile(String filename) throws IOException {
+ Properties properties = new Properties() ;
+ loadFromFile(properties, filename) ;
+ return properties ;
+ }
+
+ /** Load properties from a file if the file exists */
+ static public void loadFromFile(Properties properties, String filename) throws IOException {
+ Objects.requireNonNull(filename, "File name must not be null") ;
+ if ( "-".equals(filename) )
+ throw new IllegalArgumentException("Filename is \"-\" (stdin not supported)") ;
+
+ try (InputStream in = new FileInputStream(filename); Reader r = IO.asBufferedUTF8(in);) {
+ properties.load(r) ;
+ }
+ }
+
+ static public void storeToFile(Properties properties, String comment, String filename) throws IOException {
+ String str = comment ;
+ if ( str == null )
+ str = filename ;
+ try (FileOutputStream fos = new FileOutputStream(filename)) {
+ Writer w = IO.asBufferedUTF8(fos) ;
+ properties.store(w, "Metadata: " + str) ;
+ w.flush() ;
+ }
+ }
+
+ public static int getPropertyAsInteger(Properties properties, String key) {
+ String x = properties.getProperty(key) ;
+ if ( x == null )
+ throw new AtlasException("No such property key: " + key) ;
+ return Integer.parseInt(x) ;
+ }
+
+ public static int getPropertyAsInteger(Properties properties, String key, int defaultValue) {
+ String x = properties.getProperty(key) ;
+ if ( x == null )
+ return defaultValue ;
+ return Integer.parseInt(x) ;
+ }
+
+ public static boolean getPropertyAsBoolean(Properties properties, String key, boolean dftValue) {
+ String x = properties.getProperty(key) ;
+ if ( x == null )
+ return dftValue ;
+ if ( x.equalsIgnoreCase("true") )
+ return true ;
+ if ( x.equalsIgnoreCase("false") )
+ return true ;
+ throw new AtlasException("Value '" + x + "'not recognized for " + key) ;
+ }
+
+ public static Boolean getPropertyAsBoolean(Properties properties, String key) {
+ String x = properties.getProperty(key) ;
+ if ( x == null )
+ throw new AtlasException("No such property key: " + key) ;
+ if ( x.equalsIgnoreCase("true") )
+ return true ;
+ if ( x.equalsIgnoreCase("false") )
+ return true ;
+ throw new AtlasException("Value '" + x + "'not recognized for " + key) ;
+ }
+
+ /** Test whether a property has a value. Null tests equal to not present. */
+ public boolean propertyEquals(Properties properties, String key, String value) {
+ return Lib.equal(properties.getProperty(key), value) ;
+ }
+
+ /** Set property if not already set. */
+ public void ensurePropertySet(Properties properties, String key, String expected) {
+ getOrSetDefault(properties, key, expected) ;
+ }
+
+ /**
+ * Get property or the default value - also set the default value if not
+ * present
+ */
+ public String getOrSetDefault(Properties properties, String key, String expected) {
+ String x = properties.getProperty(key) ;
+ if ( x == null ) {
+ properties.setProperty(key, expected) ;
+ x = expected ;
+ }
+ return x ;
+ }
+
+ /** Check property is an expected value or set if missing */
+ public void checkOrSetProperty(Properties properties, String key, String expected) {
+ String x = properties.getProperty(key) ;
+ if ( x == null ) {
+ properties.setProperty(key, expected) ;
+ return ;
+ }
+ if ( x.equals(expected) )
+ return ;
+
+ inconsistent(properties, key, x, expected) ;
+ }
+
+ /** Check property has the vakue given - throw exception if not. */
+ public void checkMetadata(Properties properties, String key, String expected) {
+ String value = properties.getProperty(key) ;
+
+ if ( !Lib.equal(value, value) )
+ inconsistent(properties, key, value, expected) ;
+ }
+
+ private void inconsistent(Properties properties, String key, String actual, String expected) {
+ String msg = String.format("Inconsistent: key=%s value=%s expected=%s", key, (actual == null ? "<null>" : actual),
+ (expected == null ? "<null>" : expected)) ;
+ throw new AtlasException(msg) ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/RandomLib.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/RandomLib.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/RandomLib.java
new file mode 100644
index 0000000..d2b3516
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/RandomLib.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.security.SecureRandom ;
+import java.util.Random ;
+
+public class RandomLib
+{
+ private RandomLib() {}
+
+ /** Single instance, pure random generator */
+ public static final Random random = new SecureRandom() ;
+
+ /** Random numbers, good seed, cheaper allocation */
+ public static final Random qrandom = randInit() ;
+
+ private static Random randInit()
+ {
+ // Cheap random numbers, well seeded.
+ int seed = random.nextInt() ;
+ return new Random(seed) ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Ref.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Ref.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Ref.java
new file mode 100644
index 0000000..e25b145
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Ref.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+
+/** A mutable container */
+public class Ref<T>
+{
+ private T value ;
+
+ public T getValue() { return value; }
+
+ public Ref(T initial)
+ { setValue(initial); }
+
+ public void setValue(T value)
+ { this.value = value; }
+
+
+ // hashCode and equality are defined on object pointers.
+// @Override
+// public int hashCode() { return value.hashCode()^0x1 ; }
+//
+// @Override
+// public boolean equals(Object other)
+// {
+// if ( !( other instanceof Ref ) )
+// return false ;
+// Ref<?> r = (Ref<?>)other ;
+// return Lib.equals(value, r.value) ;
+// }
+
+ @Override
+ public String toString()
+ {
+ return "ref:"+value.toString() ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/RefLong.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/RefLong.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/RefLong.java
new file mode 100644
index 0000000..30dc663
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/RefLong.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+public final class RefLong
+{
+ private long value ;
+ public RefLong() { this(0) ; }
+ public RefLong(long v) { value = v ; }
+ public long value() { return value ; }
+ public void inc() { value++ ; }
+ public void dec() { --value ; }
+ public long getAndInc() { return value++ ; }
+ public long incAndGet() { return ++value ; }
+ public long getAndDec() { return value-- ; }
+ public long decAndGet() { return --value ; }
+ public void add(long v) { value += v ; }
+ public void subtract(long v) { value -= v ; }
+ public void set(long v) { value = v ; }
+ @Override public String toString() { return "Ref:"+Long.toString(value) ; }
+ // hashCode and equals are Object equality - this is a mutable object
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/Registry.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/Registry.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/Registry.java
new file mode 100644
index 0000000..b1e0d74
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Registry.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.Collection ;
+import java.util.Map ;
+import java.util.concurrent.ConcurrentHashMap ;
+
+public class Registry<K,T>
+{
+ protected Map<K, T> registry = new ConcurrentHashMap<>() ;
+
+ public Registry() {}
+
+ public void put(K key, T value) { registry.put(key, value) ; }
+ public T get(K key) { return registry.get(key) ; }
+ public boolean isRegistered(K key) { return registry.containsKey(key) ; }
+ public void remove(K key) { registry.remove(key) ; }
+ public Collection<K> keys() { return registry.keySet() ; }
+ //public Iterator<String> keys() { return registry.keySet().iterator() ; }
+ public int size() { return registry.size() ; }
+ public boolean isEmpty() { return registry.isEmpty() ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/1320f8db/jena-base/src/main/java/org/apache/jena/atlas/lib/ReverseComparator.java
----------------------------------------------------------------------
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/ReverseComparator.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/ReverseComparator.java
new file mode 100644
index 0000000..7019b68
--- /dev/null
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/ReverseComparator.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.atlas.lib;
+
+import java.util.Comparator ;
+
+/** Comparator that compares the other way round to it's sub-comparator */
+public class ReverseComparator<T> implements Comparator<T>
+{
+ private final Comparator<T> comparator ;
+
+ public ReverseComparator(Comparator<T> comparator)
+ {
+ this.comparator = comparator ;
+ }
+
+ @Override
+ public int compare(T o1, T o2)
+ {
+ return comparator.compare(o2, o1) ;
+ }
+}