You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metamodel.apache.org by ka...@apache.org on 2013/07/22 10:10:53 UTC
[40/64] [partial] Hard rename of all 'org/eobjects' folders to
'org/apache'.
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/FileHelper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/FileHelper.java b/core/src/main/java/org/apache/metamodel/util/FileHelper.java
new file mode 100644
index 0000000..229baeb
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/FileHelper.java
@@ -0,0 +1,460 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PushbackInputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Various helper methods for handling files
+ */
+public final class FileHelper {
+
+ private final static Logger logger = LoggerFactory.getLogger(FileHelper.class);
+
+ public static final String UTF_8_ENCODING = "UTF-8";
+ public static final String UTF_16_ENCODING = "UTF-16";
+ public static final String US_ASCII_ENCODING = "US-ASCII";
+ public static final String ISO_8859_1_ENCODING = "ISO_8859_1";
+ public static final String DEFAULT_ENCODING = UTF_8_ENCODING;
+
+ private FileHelper() {
+ // prevent instantiation
+ }
+
+ public static File createTempFile(String prefix, String suffix) {
+ try {
+ return File.createTempFile(prefix, suffix);
+ } catch (IOException e) {
+ logger.error("Could not create tempFile", e);
+ File tempDir = getTempDir();
+ return new File(tempDir, prefix + '.' + suffix);
+ }
+ }
+
+ public static File getTempDir() {
+ File result = null;
+ String tmpDirPath = System.getProperty("java.io.tmpdir");
+ if (tmpDirPath != null && !"".equals(tmpDirPath)) {
+ result = new File(tmpDirPath);
+ } else {
+ logger.debug("Could not determine tmpdir by using environment variable.");
+ try {
+ File file = File.createTempFile("foo", "bar");
+ result = file.getParentFile();
+ if (!file.delete()) {
+ logger.warn("Could not delete temp file '{}'", file.getAbsolutePath());
+ }
+ } catch (IOException e) {
+ logger.error("Could not create tempFile in order to find temporary dir", e);
+ result = new File("metamodel.tmp.dir");
+ if (!result.mkdir()) {
+ throw new IllegalStateException("Could not create directory for temporary files: " + result.getName());
+ }
+ result.deleteOnExit();
+ }
+ }
+ if (logger.isInfoEnabled()) {
+ logger.info("Using '{}' as tmpdir.", result.getAbsolutePath());
+ }
+ return result;
+ }
+
+ public static Writer getWriter(File file, String encoding, boolean append) throws IllegalStateException {
+ boolean insertBom = !append;
+ return getWriter(file, encoding, append, insertBom);
+ }
+
+ public static Writer getWriter(OutputStream outputStream, String encoding) throws IllegalStateException {
+ return getWriter(outputStream, encoding, false);
+ }
+
+ public static Writer getWriter(OutputStream outputStream, String encoding, boolean insertBom) throws IllegalStateException {
+ if (!(outputStream instanceof BufferedOutputStream)) {
+ outputStream = new BufferedOutputStream(outputStream);
+ }
+
+ try {
+ if (insertBom) {
+ Writer writer = new UnicodeWriter(outputStream, encoding);
+ return writer;
+ } else {
+ Writer writer = new OutputStreamWriter(outputStream, encoding);
+ return writer;
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static Writer getWriter(File file, String encoding, boolean append, boolean insertBom) throws IllegalStateException {
+ if (append && insertBom) {
+ throw new IllegalArgumentException("Can not insert BOM into appending writer");
+ }
+ final OutputStream outputStream = getOutputStream(file, append);
+ return getWriter(outputStream, encoding, insertBom);
+
+ }
+
+ public static Writer getWriter(File file, String encoding) throws IllegalStateException {
+ return getWriter(file, encoding, false);
+ }
+
+ public static Reader getReader(InputStream inputStream, String encoding) throws IllegalStateException {
+ try {
+ if (encoding == null || encoding.toLowerCase().indexOf("utf") != -1) {
+ byte bom[] = new byte[4];
+ int unread;
+
+ // auto-detect byte-order-mark
+ PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream, bom.length);
+ int n = pushbackInputStream.read(bom, 0, bom.length);
+
+ // Read ahead four bytes and check for BOM marks.
+ if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) {
+ encoding = "UTF-8";
+ unread = n - 3;
+ } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
+ encoding = "UTF-16BE";
+ unread = n - 2;
+ } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
+ encoding = "UTF-16LE";
+ unread = n - 2;
+ } else if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE)
+ && (bom[3] == (byte) 0xFF)) {
+ encoding = "UTF-32BE";
+ unread = n - 4;
+ } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00)
+ && (bom[3] == (byte) 0x00)) {
+ encoding = "UTF-32LE";
+ unread = n - 4;
+ } else {
+ unread = n;
+ }
+
+ if (unread > 0) {
+ pushbackInputStream.unread(bom, (n - unread), unread);
+ } else if (unread < -1) {
+ pushbackInputStream.unread(bom, 0, 0);
+ }
+
+ inputStream = pushbackInputStream;
+ }
+
+ final InputStreamReader inputStreamReader;
+ if (encoding == null) {
+ inputStreamReader = new InputStreamReader(inputStream);
+ } else {
+ inputStreamReader = new InputStreamReader(inputStream, encoding);
+ }
+ return inputStreamReader;
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static Reader getReader(File file, String encoding) throws IllegalStateException {
+ final InputStream inputStream;
+ try {
+ inputStream = new BufferedInputStream(new FileInputStream(file));
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ return getReader(inputStream, encoding);
+ }
+
+ public static String readInputStreamAsString(InputStream inputStream, String encoding) throws IllegalStateException {
+ Reader reader = getReader(inputStream, encoding);
+ return readAsString(reader);
+ }
+
+ public static String readFileAsString(File file, String encoding) throws IllegalStateException {
+ Reader br = getReader(file, encoding);
+ return readAsString(br);
+ }
+
+ public static String readAsString(Reader reader) throws IllegalStateException {
+ final BufferedReader br = getBufferedReader(reader);
+ try {
+ StringBuilder sb = new StringBuilder();
+ boolean firstLine = true;
+ for (String line = br.readLine(); line != null; line = br.readLine()) {
+ if (firstLine) {
+ firstLine = false;
+ } else {
+ sb.append('\n');
+ }
+ sb.append(line);
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ } finally {
+ safeClose(br, reader);
+ }
+ }
+
+ public static void safeClose(Object... objects) {
+ boolean debugEnabled = logger.isDebugEnabled();
+
+ if (objects == null || objects.length == 0) {
+ logger.info("safeClose(...) was invoked with null or empty array: {}", objects);
+ return;
+ }
+
+ for (Object obj : objects) {
+ if (obj != null) {
+ if (debugEnabled) {
+ logger.debug("Trying to safely close {}", obj);
+ }
+
+ if (obj instanceof Flushable) {
+ try {
+ ((Flushable) obj).flush();
+ } catch (Exception e) {
+ if (debugEnabled) {
+ logger.debug("Flushing Flushable failed", e);
+ }
+ }
+ }
+
+ if (obj instanceof Closeable) {
+ try {
+ ((Closeable) obj).close();
+ } catch (IOException e) {
+ if (debugEnabled) {
+ logger.debug("Closing Closeable failed", e);
+ }
+ }
+ } else if (obj instanceof Connection) {
+ try {
+ ((Connection) obj).close();
+ } catch (Exception e) {
+ if (debugEnabled) {
+ logger.debug("Closing Connection failed", e);
+ }
+ }
+ } else if (obj instanceof Statement) {
+ try {
+ ((Statement) obj).close();
+ } catch (Exception e) {
+ if (debugEnabled) {
+ logger.debug("Closing Statement failed", e);
+ }
+ }
+ } else if (obj instanceof ResultSet) {
+ try {
+ ((ResultSet) obj).close();
+ } catch (Exception e) {
+ if (debugEnabled) {
+ logger.debug("Closing ResultSet failed", e);
+ }
+ }
+ } else {
+ logger.info("obj was neither Closeable, Connection, Statement or ResultSet.");
+
+ try {
+ Method method = obj.getClass().getMethod("close", new Class[0]);
+ if (method == null) {
+ logger.info("obj did not have a close() method, ignoring");
+ } else {
+ method.setAccessible(true);
+ method.invoke(obj);
+ }
+ } catch (InvocationTargetException e) {
+ logger.warn("Invoking close() by reflection threw exception", e);
+ } catch (Exception e) {
+ logger.warn("Could not invoke close() by reflection", e);
+ }
+ }
+ }
+
+ }
+ }
+
+ public static BufferedWriter getBufferedWriter(File file, String encoding) throws IllegalStateException {
+ Writer writer = getWriter(file, encoding);
+ return new BufferedWriter(writer);
+ }
+
+ public static BufferedReader getBufferedReader(File file, String encoding) throws IllegalStateException {
+ Reader reader = getReader(file, encoding);
+ return new BufferedReader(reader);
+ }
+
+ public static BufferedReader getBufferedReader(InputStream inputStream, String encoding) throws IllegalStateException {
+ Reader reader = getReader(inputStream, encoding);
+ return new BufferedReader(reader);
+ }
+
+ public static Reader getReader(File file) throws IllegalStateException {
+ return getReader(file, DEFAULT_ENCODING);
+ }
+
+ public static String readFileAsString(File file) throws IllegalStateException {
+ return readFileAsString(file, DEFAULT_ENCODING);
+ }
+
+ public static BufferedWriter getBufferedWriter(File file) throws IllegalStateException {
+ return getBufferedWriter(file, DEFAULT_ENCODING);
+ }
+
+ public static Writer getWriter(File file) throws IllegalStateException {
+ return getWriter(file, DEFAULT_ENCODING);
+ }
+
+ public static void writeString(OutputStream outputStream, String string) throws IllegalStateException {
+ writeString(outputStream, string, DEFAULT_ENCODING);
+ }
+
+ public static void writeString(OutputStream outputStream, String string, String encoding) throws IllegalStateException {
+ final Writer writer = getWriter(outputStream, encoding);
+ writeString(writer, string, encoding);
+ }
+
+ public static void writeString(Writer writer, String string) throws IllegalStateException {
+ writeString(writer, string, DEFAULT_ENCODING);
+ }
+
+ public static void writeString(Writer writer, String string, String encoding) throws IllegalStateException {
+ try {
+ writer.write(string);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ } finally {
+ safeClose(writer);
+ }
+ }
+
+ public static void writeStringAsFile(File file, String string) throws IllegalStateException {
+ writeStringAsFile(file, string, DEFAULT_ENCODING);
+ }
+
+ public static void writeStringAsFile(File file, String string, String encoding) throws IllegalStateException {
+ final BufferedWriter bw = getBufferedWriter(file, encoding);
+ writeString(bw, string, encoding);
+ }
+
+ public static BufferedReader getBufferedReader(File file) throws IllegalStateException {
+ return getBufferedReader(file, DEFAULT_ENCODING);
+ }
+
+ public static void copy(Reader reader, Writer writer) throws IllegalStateException {
+ final BufferedReader bufferedReader = getBufferedReader(reader);
+ try {
+ boolean firstLine = true;
+ for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) {
+ if (firstLine) {
+ firstLine = false;
+ } else {
+ writer.write('\n');
+ }
+ writer.write(line);
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static BufferedReader getBufferedReader(Reader reader) {
+ if (reader instanceof BufferedReader) {
+ return (BufferedReader) reader;
+ }
+ return new BufferedReader(reader);
+ }
+
+ public static void copy(InputStream fromStream, OutputStream toStream) throws IllegalStateException {
+ try {
+ byte[] buffer = new byte[1024 * 32];
+ for (int read = fromStream.read(buffer); read != -1; read = fromStream.read(buffer)) {
+ toStream.write(buffer, 0, read);
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static void copy(File from, File to) throws IllegalStateException {
+ assert from.exists();
+
+ final InputStream fromStream = getInputStream(from);
+ final OutputStream toStream = getOutputStream(to);
+
+ try {
+ copy(fromStream, toStream);
+ } finally {
+ safeClose(fromStream, toStream);
+ }
+ }
+
+ public static OutputStream getOutputStream(File file) throws IllegalStateException {
+ return getOutputStream(file, false);
+ }
+
+ public static OutputStream getOutputStream(File file, boolean append) {
+ try {
+ return new BufferedOutputStream(new FileOutputStream(file, append));
+ } catch (FileNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static InputStream getInputStream(File file) throws IllegalStateException {
+ try {
+ return new BufferedInputStream(new FileInputStream(file));
+ } catch (FileNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static byte[] readAsBytes(InputStream inputStream) {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ copy(inputStream, baos);
+ } finally {
+ safeClose(inputStream);
+ }
+ return baos.toByteArray();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/FileResource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/FileResource.java b/core/src/main/java/org/apache/metamodel/util/FileResource.java
new file mode 100644
index 0000000..bf17c8f
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/FileResource.java
@@ -0,0 +1,138 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+
+/**
+ * {@link File} based {@link Resource} implementation.
+ */
+public class FileResource implements Resource, Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private final File _file;
+
+ public FileResource(String filename) {
+ _file = new File(filename);
+ }
+
+ public FileResource(File file) {
+ _file = file;
+ }
+
+ @Override
+ public String toString() {
+ return "FileResource[" + _file.getPath() + "]";
+ }
+
+ @Override
+ public String getName() {
+ return _file.getName();
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ if (!isExists()) {
+ return false;
+ }
+ boolean canWrite = _file.canWrite();
+ return !canWrite;
+ }
+
+ @Override
+ public void write(Action<OutputStream> writeCallback) throws ResourceException {
+ final OutputStream out = FileHelper.getOutputStream(_file);
+ try {
+ writeCallback.run(out);
+ } catch (Exception e) {
+ throw new ResourceException(this, "Error occurred in write callback", e);
+ } finally {
+ FileHelper.safeClose(out);
+ }
+ }
+
+ @Override
+ public void append(Action<OutputStream> appendCallback) {
+ final OutputStream out = FileHelper.getOutputStream(_file, true);
+ try {
+ appendCallback.run(out);
+ } catch (Exception e) {
+ throw new ResourceException(this, "Error occurred in append callback", e);
+ } finally {
+ FileHelper.safeClose(out);
+ }
+ }
+
+ @Override
+ public void read(Action<InputStream> readCallback) {
+ final InputStream in = read();
+ try {
+ readCallback.run(in);
+ } catch (Exception e) {
+ throw new ResourceException(this, "Error occurred in read callback", e);
+ } finally {
+ FileHelper.safeClose(in);
+ }
+ }
+
+ @Override
+ public <E> E read(Func<InputStream, E> readCallback) {
+ final InputStream in = read();
+ try {
+ final E result = readCallback.eval(in);
+ return result;
+ } catch (Exception e) {
+ throw new ResourceException(this, "Error occurred in read callback", e);
+ } finally {
+ FileHelper.safeClose(in);
+ }
+ }
+
+ public File getFile() {
+ return _file;
+ }
+
+ @Override
+ public boolean isExists() {
+ return _file.exists();
+ }
+
+ @Override
+ public long getSize() {
+ return _file.length();
+ }
+
+ @Override
+ public long getLastModified() {
+ final long lastModified = _file.lastModified();
+ if (lastModified == 0) {
+ return -1;
+ }
+ return lastModified;
+ }
+
+ @Override
+ public InputStream read() throws ResourceException {
+ final InputStream in = FileHelper.getInputStream(_file);
+ return in;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/FormatHelper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/FormatHelper.java b/core/src/main/java/org/apache/metamodel/util/FormatHelper.java
new file mode 100644
index 0000000..3b954dc
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/FormatHelper.java
@@ -0,0 +1,273 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Date;
+
+import org.eobjects.metamodel.query.QueryParameter;
+import org.eobjects.metamodel.schema.ColumnType;
+
+/**
+ * Helper class for formatting
+ */
+public final class FormatHelper {
+
+ /**
+ * Creates a uniform number format which is similar to that of eg. Java
+ * doubles. The format will not include thousand separators and it will use
+ * a dot as a decimal separator.
+ *
+ * @return
+ */
+ public static NumberFormat getUiNumberFormat() {
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ symbols.setDecimalSeparator('.');
+ DecimalFormat format = new DecimalFormat("###.##", symbols);
+ format.setGroupingUsed(false);
+ return format;
+ }
+
+ public static NumberFormat getSqlNumberFormat() {
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ symbols.setDecimalSeparator('.');
+ DecimalFormat format = new DecimalFormat("###.##", symbols);
+ format.setGroupingUsed(false);
+ format.setMaximumFractionDigits(100);
+ return format;
+ }
+
+ public static String formatSqlBoolean(ColumnType columnType, boolean b) {
+ if (columnType == ColumnType.BIT) {
+ if (b) {
+ return "1";
+ } else {
+ return "0";
+ }
+ } else {
+ if (b) {
+ return "TRUE";
+ } else {
+ return "FALSE";
+ }
+ }
+ }
+
+ /**
+ * Formats a date according to a specific column type (DATE, TIME or
+ * TIMESTAMP)
+ *
+ * @param columnType
+ * the column type
+ * @param date
+ * the date value
+ * @return
+ */
+ public static String formatSqlTime(ColumnType columnType, Date date) {
+ return formatSqlTime(columnType, date, true);
+ }
+
+ /**
+ * Formats a date according to a specific column type (DATE, TIME or
+ * TIMESTAMP)
+ *
+ * @param columnType
+ * the column type
+ * @param date
+ * the date value
+ * @param typeCastDeclaration
+ * whether or not to include a type cast declaration
+ * @param beforeDateLiteral
+ * before date literal
+ * @param afterDateLiteral
+ * after date literal
+ * @return
+ */
+ public static String formatSqlTime(ColumnType columnType, Date date,
+ boolean typeCastDeclaration, String beforeDateLiteral,
+ String afterDateLiteral) {
+ if (columnType == null) {
+ throw new IllegalArgumentException("Column type cannot be null");
+ }
+ final DateFormat format;
+ final String typePrefix;
+ switch (columnType) {
+ case DATE:
+ format = DateUtils.createDateFormat("yyyy-MM-dd");
+ typePrefix = "DATE";
+ break;
+ case TIME:
+ format = DateUtils.createDateFormat("HH:mm:ss");
+ typePrefix = "TIME";
+ break;
+ case TIMESTAMP:
+ format = DateUtils.createDateFormat("yyyy-MM-dd HH:mm:ss");
+ typePrefix = "TIMESTAMP";
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Cannot format time value of type: " + columnType);
+ }
+
+ if (typeCastDeclaration) {
+ return typePrefix + " " + beforeDateLiteral + format.format(date) + afterDateLiteral;
+ } else {
+ return format.format(date);
+ }
+ }
+
+ /**
+ * Formats a date according to a specific column type (DATE, TIME or TIMESTAMP). For backward compatibility.
+ * @param columnType
+ * @param date
+ * @param typeCastDeclaration
+ * @return
+ */
+ public static String formatSqlTime(ColumnType columnType, Date date, boolean typeCastDeclaration) {
+ return formatSqlTime(columnType, date, typeCastDeclaration, "\'", "\'");
+ }
+
+ /**
+ * Parses a SQL string representation of a time based value
+ *
+ * @param type
+ * @param value
+ * @return
+ */
+ public static Date parseSqlTime(ColumnType columnType, String value) {
+ final String[] formats;
+ switch (columnType) {
+ case DATE:
+ formats = new String[] { "yyyy-MM-dd", };
+ break;
+ case TIME:
+ formats = new String[] { "HH:mm:ss", "HH:mm" };
+ break;
+ case TIMESTAMP:
+ formats = new String[] { "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm",
+ "yyyy-MM-dd" };
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Cannot parse time value of type: " + columnType);
+ }
+
+ for (String format : formats) {
+ try {
+ DateFormat dateFormat = DateUtils.createDateFormat(format);
+ return dateFormat.parse(value);
+ } catch (ParseException e) {
+ // proceed to next format
+ }
+ }
+
+ throw new IllegalArgumentException("String value '" + value
+ + "' not parseable as a " + columnType);
+ }
+
+ public static String formatSqlValue(ColumnType columnType, Object value) {
+ if (value == null) {
+ return "NULL";
+ }
+ if (value instanceof QueryParameter) {
+ return value.toString();
+ }
+ if (value.getClass().isArray()) {
+ value = CollectionUtils.toList(value);
+ }
+ if (value instanceof Iterable) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('(');
+ for (Object item : (Iterable<?>) value) {
+ if (sb.length() > 1) {
+ sb.append(" , ");
+ }
+ sb.append(formatSqlValue(columnType, item));
+ }
+ sb.append(')');
+ return sb.toString();
+ } else if (isNumber(columnType, value)) {
+ NumberFormat numberFormat = getSqlNumberFormat();
+ Number n = NumberComparator.toNumber(value);
+ if (n == null) {
+ throw new IllegalStateException("Could not convert " + value
+ + " to number");
+ }
+ String numberString = numberFormat.format(n);
+ return numberString;
+ } else if (isBoolean(columnType, value)) {
+ Boolean b = BooleanComparator.toBoolean(value);
+ if (b == null) {
+ throw new IllegalStateException("Could not convert " + value
+ + " to boolean");
+ }
+ String booleanString = formatSqlBoolean(columnType, b);
+ return booleanString;
+ } else if (isTimeBased(columnType, value)) {
+ Date date = TimeComparator.toDate(value);
+ if (date == null) {
+ throw new IllegalStateException("Could not convert " + value
+ + " to date");
+ }
+ String timeString = formatSqlTime(columnType, date);
+ return timeString;
+ } else if (isLiteral(columnType, value)) {
+ return '\'' + value.toString() + '\'';
+ } else {
+ if (columnType == null) {
+ throw new IllegalStateException("Value type not supported: "
+ + value);
+ }
+ throw new IllegalStateException("Column type not supported: "
+ + columnType);
+ }
+ }
+
+ private static boolean isTimeBased(ColumnType columnType, Object operand) {
+ if (columnType == null) {
+ return TimeComparator.isTimeBased(operand);
+ }
+ return columnType.isTimeBased();
+ }
+
+ private static boolean isBoolean(ColumnType columnType, Object operand) {
+ if (columnType == null) {
+ return operand instanceof Boolean;
+ }
+ return columnType.isBoolean();
+ }
+
+ private static boolean isNumber(ColumnType columnType, Object operand) {
+ if (columnType == null) {
+ return operand instanceof Number;
+ }
+ return columnType.isNumber();
+ }
+
+ private static boolean isLiteral(ColumnType columnType, Object operand) {
+ if (columnType == null) {
+ return operand instanceof String;
+ }
+ return columnType.isLiteral();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/Func.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/Func.java b/core/src/main/java/org/apache/metamodel/util/Func.java
new file mode 100644
index 0000000..c576456
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/Func.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.eobjects.metamodel.util;
+
+/**
+ * Represents an abstract function, which is an executable piece of
+ * functionality that has an input and an output. A {@link Func} has a return
+ * type, unlike an {@link Action}.
+ *
+ * @author Kasper Sørensen
+ *
+ * @param <I>
+ * the input type
+ * @param <O>
+ * the output type
+ */
+public interface Func<I, O> {
+
+ /**
+ * Evaluates an element and transforms it using this function.
+ *
+ * @param arg
+ * the input given to the function
+ * @return the output result of the function
+ */
+ public O eval(I arg);
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/HasName.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/HasName.java b/core/src/main/java/org/apache/metamodel/util/HasName.java
new file mode 100644
index 0000000..647848f
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/HasName.java
@@ -0,0 +1,29 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+/**
+ * Represents anything with a (String based) name.
+ *
+ * @author Kasper Sørensen
+ */
+public interface HasName {
+
+ public String getName();
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/HasNameMapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/HasNameMapper.java b/core/src/main/java/org/apache/metamodel/util/HasNameMapper.java
new file mode 100644
index 0000000..3b22a32
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/HasNameMapper.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.eobjects.metamodel.util;
+
+import java.io.Serializable;
+
+/**
+ * {@link Func} useful for mapping {@link HasName} instances to names, using
+ * {@link CollectionUtils#map(Object[], Func)} and
+ * {@link CollectionUtils#map(Iterable, Func)}.
+ *
+ * @author Kasper Sørensen
+ */
+public final class HasNameMapper implements Func<HasName, String>, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public String eval(HasName arg) {
+ return arg.getName();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/ImmutableDate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/ImmutableDate.java b/core/src/main/java/org/apache/metamodel/util/ImmutableDate.java
new file mode 100644
index 0000000..4ed34a6
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/ImmutableDate.java
@@ -0,0 +1,63 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+/**
+ * A Date implementation that is immutable and has a predictable
+ * (locale-indifferent) toString() method.
+ *
+ * @author Kasper Sørensen
+ *
+ * @deprecated MetaModel is not a Date API, use Joda time or live with
+ * java.util.Date.
+ */
+@Deprecated
+public final class ImmutableDate extends Date {
+
+ private static final long serialVersionUID = 1L;
+
+ public ImmutableDate(long time) {
+ super(time);
+ }
+
+ public ImmutableDate(Date date) {
+ super(date.getTime());
+ }
+
+ /**
+ * This mutator will throw an {@link UnsupportedOperationException}, since
+ * the date is ummutable.
+ *
+ * @param time
+ * new time to set
+ */
+ @Override
+ public void setTime(long time) {
+ throw new UnsupportedOperationException("setTime(...) is not allowed");
+ }
+
+ @Override
+ public String toString() {
+ DateFormat format = DateUtils.createDateFormat();
+ return format.format(this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/ImmutableRef.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/ImmutableRef.java b/core/src/main/java/org/apache/metamodel/util/ImmutableRef.java
new file mode 100644
index 0000000..e8653cf
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/ImmutableRef.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.eobjects.metamodel.util;
+
+/**
+ * Simple/hard implementation of the {@link Ref} interface.
+ *
+ * @author Kasper Sørensen
+ *
+ * @param <E>
+ */
+public final class ImmutableRef<E> implements Ref<E> {
+
+ private final E _object;
+
+ public ImmutableRef(E object) {
+ _object = object;
+ }
+
+ @Override
+ public E get() {
+ return _object;
+ }
+
+ public static <E> Ref<E> of(E object) {
+ return new ImmutableRef<E>(object);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/InMemoryResource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/InMemoryResource.java b/core/src/main/java/org/apache/metamodel/util/InMemoryResource.java
new file mode 100644
index 0000000..3a8d138
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/InMemoryResource.java
@@ -0,0 +1,160 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+
+/**
+ * An entirely in-memory kept {@link Resource}.
+ */
+public class InMemoryResource implements Resource, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String _path;
+ private byte[] _contents;
+ private long _lastModified;
+
+ /**
+ * Constructs a new {@link InMemoryResource} with a path/name
+ *
+ * @param path
+ */
+ public InMemoryResource(String path) {
+ this(path, new byte[0], -1);
+ }
+
+ /**
+ * Constructs a new {@link InMemoryResource} with a path/name and some
+ * initial contents.
+ *
+ * @param path
+ * @param contents
+ * @param lastModified
+ */
+ public InMemoryResource(String path, byte[] contents, long lastModified) {
+ _path = path;
+ _contents = contents;
+ _lastModified = lastModified;
+ }
+
+ @Override
+ public String toString() {
+ return "InMemoryResource[" + _path + "]";
+ }
+
+ @Override
+ public String getName() {
+ String name = _path;
+ final int lastSlash = name.lastIndexOf('/');
+ final int lastBackSlash = name.lastIndexOf('\\');
+ final int lastIndex = Math.max(lastSlash, lastBackSlash);
+ if (lastIndex != -1) {
+ final String lastPart = name.substring(lastIndex + 1);
+ if (!"".equals(lastPart)) {
+ return lastPart;
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Gets the path of this resource
+ *
+ * @return
+ */
+ public String getPath() {
+ return _path;
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return false;
+ }
+
+ @Override
+ public boolean isExists() {
+ return true;
+ }
+
+ @Override
+ public long getSize() {
+ return _contents.length;
+ }
+
+ @Override
+ public long getLastModified() {
+ return _lastModified;
+ }
+
+ @Override
+ public void write(Action<OutputStream> writeCallback) throws ResourceException {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ writeCallback.run(baos);
+ _contents = baos.toByteArray();
+ _lastModified = System.currentTimeMillis();
+ } catch (Exception e) {
+ throw new ResourceException(this, e);
+ }
+ }
+
+ @Override
+ public void append(Action<OutputStream> appendCallback) throws ResourceException {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(_contents);
+ appendCallback.run(baos);
+ _contents = baos.toByteArray();
+ _lastModified = System.currentTimeMillis();
+ } catch (Exception e) {
+ throw new ResourceException(this, e);
+ }
+ }
+
+ @Override
+ public InputStream read() throws ResourceException {
+ return new ByteArrayInputStream(_contents);
+ }
+
+ @Override
+ public void read(Action<InputStream> readCallback) throws ResourceException {
+ final InputStream inputStream = read();
+ try {
+ readCallback.run(inputStream);
+ } catch (Exception e) {
+ throw new ResourceException(this, e);
+ }
+ }
+
+ @Override
+ public <E> E read(Func<InputStream, E> readCallback) throws ResourceException {
+ final InputStream inputStream = read();
+ try {
+ return readCallback.eval(inputStream);
+ } catch (Exception e) {
+ throw new ResourceException(this, e);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/InclusionPredicate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/InclusionPredicate.java b/core/src/main/java/org/apache/metamodel/util/InclusionPredicate.java
new file mode 100644
index 0000000..03bc689
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/InclusionPredicate.java
@@ -0,0 +1,50 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * A predicate that uses an inclusion list ("white list") of elements to
+ * determine whether to evaluate true or false.
+ *
+ * @param <E>
+ */
+public class InclusionPredicate<E> implements Predicate<E> {
+
+ private final Collection<E> _inclusionList;
+
+ public InclusionPredicate(Collection<E> inclusionList) {
+ _inclusionList = inclusionList;
+ }
+
+ @Override
+ public Boolean eval(E arg) {
+ if (_inclusionList.contains(arg)) {
+ return true;
+ }
+ return false;
+ }
+
+ public Collection<E> getInclusionList() {
+ return Collections.unmodifiableCollection(_inclusionList);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/LazyRef.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/LazyRef.java b/core/src/main/java/org/apache/metamodel/util/LazyRef.java
new file mode 100644
index 0000000..ab39c66
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/LazyRef.java
@@ -0,0 +1,127 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents a lazy loaded reference.
+ *
+ * @author Kasper Sørensen
+ *
+ * @param <E>
+ */
+public abstract class LazyRef<E> implements Ref<E> {
+
+ private static final Logger logger = LoggerFactory.getLogger(LazyRef.class);
+
+ private final AtomicBoolean _fetched = new AtomicBoolean(false);
+ private volatile Throwable _error;
+ private E _object;
+
+ @Override
+ public final E get() {
+ if (!_fetched.get()) {
+ synchronized (_fetched) {
+ if (!_fetched.get()) {
+ try {
+ _object = fetch();
+ } catch (Throwable t) {
+ _error = t;
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ }
+ logger.warn("Failed to fetch value: " + this + ". Reporting error.", t);
+ } finally {
+ _fetched.set(true);
+ }
+ }
+ }
+ }
+ return _object;
+ }
+
+ protected abstract E fetch() throws Throwable;
+
+ /**
+ * Gets whether the lazy loaded reference has been loaded or not.
+ *
+ * @return a boolean indicating whether or not the reference has been loaded
+ * or not
+ */
+ public boolean isFetched() {
+ return _fetched.get();
+ }
+
+ /**
+ * Gets any error that occurred while fetching the lazy loaded value.
+ *
+ * @return
+ */
+ public Throwable getError() {
+ return _error;
+ }
+
+ /**
+ * Requests an asynchronous load of the lazy reference. If not already
+ * loaded, this will cause another thread to load the reference, typically
+ * to make it immediately available for later evaluation.
+ *
+ * @param errorAction
+ * an optional error action to invoke if an exception is thrown
+ * during loading of the reference.
+ */
+ public void requestLoad(final Action<Throwable> errorAction) {
+ if (!isFetched()) {
+ ExecutorService executorService = SharedExecutorService.get();
+ executorService.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ get();
+ } catch (RuntimeException e) {
+ // do nothing, the exception will be handled via _error
+ // below
+ }
+ if (_error != null && errorAction != null) {
+ try {
+ errorAction.run(_error);
+ } catch (Exception e) {
+ logger.error("Error handling action failed!", e);
+ }
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Requests an asynchronous load of the lazy reference. If not already
+ * loaded, this will cause another thread to load the reference, typically
+ * to make it immediately available for later evaluation.
+ */
+ public void requestLoad() {
+ requestLoad(null);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/Month.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/Month.java b/core/src/main/java/org/apache/metamodel/util/Month.java
new file mode 100644
index 0000000..3380e5f
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/Month.java
@@ -0,0 +1,94 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.util.Calendar;
+
+/**
+ * Provides a handy and type-safe enum around the months otherwise defined as
+ * int constants in java.util.Calendar.
+ *
+ * @author Kasper Sørensen
+ *
+ */
+public enum Month implements HasName {
+
+ JANUARY(Calendar.JANUARY),
+
+ FEBRUARY(Calendar.FEBRUARY),
+
+ MARCH(Calendar.MARCH),
+
+ APRIL(Calendar.APRIL),
+
+ MAY(Calendar.MAY),
+
+ JUNE(Calendar.JUNE),
+
+ JULY(Calendar.JULY),
+
+ AUGUST(Calendar.AUGUST),
+
+ SEPTEMBER(Calendar.SEPTEMBER),
+
+ OCTOBER(Calendar.OCTOBER),
+
+ NOVEMBER(Calendar.NOVEMBER),
+
+ DECEMBER(Calendar.DECEMBER);
+
+ private int calendarConstant;
+
+ private Month(int calendarConstant) {
+ this.calendarConstant = calendarConstant;
+ }
+
+ public int getCalendarConstant() {
+ return calendarConstant;
+ }
+
+ public static Month getByCalendarConstant(int calendarConstant) {
+ for (Month month : values()) {
+ if (month.getCalendarConstant() == calendarConstant) {
+ return month;
+ }
+ }
+ return null;
+ }
+
+ public Month next() {
+ if (this == DECEMBER) {
+ return JANUARY;
+ }
+ return values()[ordinal() + 1];
+ }
+
+ public Month previous() {
+ if (this == JANUARY) {
+ return DECEMBER;
+ }
+ return values()[ordinal() - 1];
+ }
+
+ @Override
+ public String getName() {
+ final String capitalized = toString();
+ return capitalized.charAt(0) + capitalized.substring(1).toLowerCase();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/MutableRef.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/MutableRef.java b/core/src/main/java/org/apache/metamodel/util/MutableRef.java
new file mode 100644
index 0000000..81f8ea6
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/MutableRef.java
@@ -0,0 +1,48 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+/**
+ * Represents a mutable reference to any object
+ *
+ * @author Kasper Sørensen
+ *
+ * @param <E>
+ */
+public final class MutableRef<E> implements Ref<E> {
+
+ private E _object;
+
+ public MutableRef() {
+ }
+
+ public MutableRef(E object) {
+ _object = object;
+ }
+
+ @Override
+ public E get() {
+ return _object;
+ }
+
+ public void set(E object) {
+ _object = object;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/NumberComparator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/NumberComparator.java b/core/src/main/java/org/apache/metamodel/util/NumberComparator.java
new file mode 100644
index 0000000..5a1ba02
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/NumberComparator.java
@@ -0,0 +1,107 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.util.Comparator;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Comparator that can compare numbers of various kinds (short, integer, float,
+ * double etc)
+ */
+public final class NumberComparator implements Comparator<Object> {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(NumberComparator.class);
+
+ private static final Comparator<Object> _instance = new NumberComparator();
+
+ public static Comparator<Object> getComparator() {
+ return _instance;
+ }
+
+ private NumberComparator() {
+ }
+
+ public static Comparable<Object> getComparable(Object o) {
+ final Number n = toNumber(o);
+ return new Comparable<Object>() {
+
+ @Override
+ public boolean equals(Object obj) {
+ return _instance.equals(obj);
+ }
+
+ public int compareTo(Object o) {
+ return _instance.compare(n, o);
+ }
+
+ @Override
+ public String toString() {
+ return "NumberComparable[number=" + n + "]";
+ }
+
+ };
+ }
+
+ public int compare(Object o1, Object o2) {
+ if (o1 == null && o2 == null) {
+ return 0;
+ }
+ if (o1 == null) {
+ return -1;
+ }
+ if (o2 == null) {
+ return 1;
+ }
+ Number n1 = toNumber(o1);
+ Number n2 = toNumber(o2);
+ return Double.valueOf(n1.doubleValue()).compareTo(n2.doubleValue());
+ }
+
+ public static Number toNumber(Object value) {
+ if (value == null) {
+ return null;
+ } else if (value instanceof Number) {
+ return (Number) value;
+ } else if (value instanceof Boolean) {
+ if (Boolean.TRUE.equals(value)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ String stringValue = value.toString();
+ try {
+ return Integer.parseInt(stringValue);
+ } catch (NumberFormatException e1) {
+ try {
+ return Double.parseDouble(stringValue);
+ } catch (NumberFormatException e2) {
+ logger.warn(
+ "Could not convert '{}' to number, returning null",
+ value);
+ return null;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/ObjectComparator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/ObjectComparator.java b/core/src/main/java/org/apache/metamodel/util/ObjectComparator.java
new file mode 100644
index 0000000..9b15452
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/ObjectComparator.java
@@ -0,0 +1,102 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.util.Comparator;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * General purpose comparator to use for objects of various kinds. Prevents
+ * NullPointerExceptions and tries to use comparable interface if available and
+ * appropriate on incoming objects.
+ */
+public final class ObjectComparator implements Comparator<Object> {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(ObjectComparator.class);
+
+ private static final Comparator<Object> _instance = new ObjectComparator();
+
+ public static Comparator<Object> getComparator() {
+ return _instance;
+ }
+
+ private ObjectComparator() {
+ }
+
+ public static Comparable<Object> getComparable(final Object o) {
+ return new Comparable<Object>() {
+
+ @Override
+ public boolean equals(Object obj) {
+ return _instance.equals(obj);
+ }
+
+ public int compareTo(Object o2) {
+ return _instance.compare(o, o2);
+ }
+
+ @Override
+ public String toString() {
+ return "ObjectComparable[object=" + o + "]";
+ }
+ };
+ }
+
+ @SuppressWarnings("unchecked")
+ public int compare(final Object o1, final Object o2) {
+ logger.debug("compare({},{})", o1, o2);
+ if (o1 == null && o2 == null) {
+ return 0;
+ }
+ if (o1 == null) {
+ return -1;
+ }
+ if (o2 == null) {
+ return 1;
+ }
+ if (o1 instanceof Number && o1 instanceof Number) {
+ return NumberComparator.getComparator().compare(o1, o2);
+ }
+ if (TimeComparator.isTimeBased(o1) && TimeComparator.isTimeBased(o2)) {
+ return TimeComparator.getComparator().compare(o1, o2);
+ }
+ if (BooleanComparator.isBoolean(o1) && BooleanComparator.isBoolean(o2)) {
+ return BooleanComparator.getComparator().compare(o1, o2);
+ }
+ if (o1 instanceof Comparable && o2 instanceof Comparable) {
+ @SuppressWarnings("rawtypes")
+ Comparable c1 = (Comparable) o1;
+ @SuppressWarnings("rawtypes")
+ Comparable c2 = (Comparable) o2;
+ // We can only count on using the comparable interface if o1 and o2
+ // are within of the same class or if one is a subclass of the other
+ if (c1.getClass().isAssignableFrom(c2.getClass())) {
+ return c1.compareTo(o2);
+ }
+ if (o2.getClass().isAssignableFrom(c1.getClass())) {
+ return -1 * c2.compareTo(o1);
+ }
+ }
+ logger.info("Using ToStringComparator because no apparent better comparison method could be found");
+ return ToStringComparator.getComparator().compare(o1, o2);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/Predicate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/Predicate.java b/core/src/main/java/org/apache/metamodel/util/Predicate.java
new file mode 100644
index 0000000..4268c66
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/Predicate.java
@@ -0,0 +1,31 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+/**
+ * A predicate is a special type of {@link Func}, used typically for
+ * inclusion/exclusion criteria.
+ *
+ * @author Kasper Sørensen
+ *
+ * @param <E>
+ */
+public interface Predicate<E> extends Func<E, Boolean> {
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/Ref.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/Ref.java b/core/src/main/java/org/apache/metamodel/util/Ref.java
new file mode 100644
index 0000000..0e9985f
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/Ref.java
@@ -0,0 +1,32 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+/**
+ * Represents an abstract reference. This interface enables use of both regular,
+ * hard references, soft references and deferred/lazy references.
+ *
+ * @author Kasper Sørensen
+ *
+ * @param <E>
+ */
+public interface Ref<E> {
+
+ public E get();
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/Resource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/Resource.java b/core/src/main/java/org/apache/metamodel/util/Resource.java
new file mode 100644
index 0000000..8da25d6
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/Resource.java
@@ -0,0 +1,129 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Represents a resource from which we can read and write bytes
+ */
+public interface Resource extends HasName {
+
+ /**
+ * Gets the name of the resource, typically a filename or other identifying
+ * string
+ */
+ @Override
+ public String getName();
+
+ /**
+ * Determines if the file is read only, or if writes are also possible.
+ *
+ * @return
+ */
+ public boolean isReadOnly();
+
+ /**
+ * Determines if the resource referenced by this object exists or not.
+ *
+ * @return
+ */
+ public boolean isExists();
+
+ /**
+ * Gets the size (in number of bytes) of this resource's data. An
+ * approximated number is allowed.
+ *
+ * If the size is not determinable without actually reading through the
+ * whole contents of the resource, -1 is returned.
+ *
+ * @return
+ */
+ public long getSize();
+
+ /**
+ * Gets the last modified timestamp value (measured in milliseconds since
+ * the epoch (00:00:00 GMT, January 1, 1970)) of the resource, if available.
+ * If the last modified date is not available, -1 is returned.
+ *
+ * @return
+ */
+ public long getLastModified();
+
+ /**
+ * Opens up an {@link OutputStream} to write to the resource, and allows a
+ * callback to perform writing actions on it.
+ *
+ * @param writeCallback
+ * a callback which should define what to write to the resource.
+ *
+ * @throws ResourceException
+ * if an error occurs while writing
+ */
+ public void write(Action<OutputStream> writeCallback) throws ResourceException;
+
+ /**
+ * Opens up an {@link InputStream} to append (write at the end of the
+ * existing stream) to the resource.
+ *
+ * @param appendCallback
+ * a callback which should define what to append to the resource.
+ * @throws ResourceException
+ * if an error occurs while appending
+ */
+ public void append(Action<OutputStream> appendCallback) throws ResourceException;
+
+ /**
+ * Opens up an {@link InputStream} to read from the resource. Consumers of
+ * this method are expected to invoke the {@link InputStream#close()} method
+ * manually.
+ *
+ * If possible, the other read(...) methods are preferred over this one,
+ * since they guarantee proper closing of the resource's handles.
+ *
+ * @return
+ * @throws ResourceException
+ */
+ public InputStream read() throws ResourceException;
+
+ /**
+ * Opens up an {@link InputStream} to read from the resource, and allows a
+ * callback to perform writing actions on it.
+ *
+ * @param readCallback
+ *
+ * @throws ResourceException
+ * if an error occurs while reading
+ */
+ public void read(Action<InputStream> readCallback) throws ResourceException;
+
+ /**
+ * Opens up an {@link InputStream} to read from the resource, and allows a
+ * callback function to perform writing actions on it and return the
+ * function's result.
+ *
+ * @param readCallback
+ * @return the result of the function
+ *
+ * @throws ResourceException
+ * if an error occurs while reading
+ */
+ public <E> E read(Func<InputStream, E> readCallback) throws ResourceException;
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/ResourceException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/ResourceException.java b/core/src/main/java/org/apache/metamodel/util/ResourceException.java
new file mode 100644
index 0000000..4f61677
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/ResourceException.java
@@ -0,0 +1,50 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import org.eobjects.metamodel.MetaModelException;
+
+/**
+ * Exception type for errors that occur while dealing with {@link Resource}s.
+ */
+public class ResourceException extends MetaModelException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Resource _resource;
+
+ public ResourceException(Resource resource, Exception cause) {
+ super(cause);
+ _resource = resource;
+ }
+
+ public ResourceException(Resource resource,String message, Exception cause) {
+ super(message, cause);
+ _resource = resource;
+ }
+
+ public ResourceException(Resource resource,String message) {
+ super(message);
+ _resource = resource;
+ }
+
+ public Resource getResource() {
+ return _resource;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/SerializableRef.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/SerializableRef.java b/core/src/main/java/org/apache/metamodel/util/SerializableRef.java
new file mode 100644
index 0000000..3ae688e
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/SerializableRef.java
@@ -0,0 +1,90 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.io.Serializable;
+
+/**
+ * A serializable reference to an object which may or may not be serializable.
+ * Using this reference there is safety that if the object IS serializable, it
+ * will be serialized, or otherwise it will be gracefully ignored.
+ *
+ * @param <E>
+ */
+public final class SerializableRef<E> implements Ref<E>, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final E _serializableObj;
+ private final transient E _transientObj;
+
+ public SerializableRef(E obj) {
+ if (obj instanceof Serializable) {
+ _serializableObj = obj;
+ _transientObj = null;
+ } else {
+ _serializableObj = null;
+ _transientObj = obj;
+ }
+ }
+
+ @Override
+ public E get() {
+ if (_serializableObj == null) {
+ return _transientObj;
+ }
+ return _serializableObj;
+ }
+
+ public boolean isSerializing() {
+ return _serializableObj != null;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((_serializableObj == null) ? 0 : _serializableObj.hashCode());
+ result = prime * result + ((_transientObj == null) ? 0 : _transientObj.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SerializableRef<?> other = (SerializableRef<?>) obj;
+ if (_serializableObj == null) {
+ if (other._serializableObj != null)
+ return false;
+ } else if (!_serializableObj.equals(other._serializableObj))
+ return false;
+ if (_transientObj == null) {
+ if (other._transientObj != null)
+ return false;
+ } else if (!_transientObj.equals(other._transientObj))
+ return false;
+ return true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/SharedExecutorService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/SharedExecutorService.java b/core/src/main/java/org/apache/metamodel/util/SharedExecutorService.java
new file mode 100644
index 0000000..37b5aa5
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/SharedExecutorService.java
@@ -0,0 +1,78 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A shared {@link ExecutorService} for use on ad-hoc tasks that can be
+ * optimized by running operations in parallel.
+ *
+ * Note that since this {@link ExecutorService} is shared, it is not recommended
+ * to use it for dedicated tasks or daemon-like long-running tasks.
+ *
+ * @author Kasper Sørensen
+ */
+public final class SharedExecutorService {
+
+ /**
+ * A custom thread factory that creates daemon threads.
+ */
+ private static final class ThreadFactoryImpl implements ThreadFactory {
+
+ private static final AtomicInteger counter = new AtomicInteger(0);
+
+ private final ThreadGroup _threadGroup;
+
+ public ThreadFactoryImpl() {
+ SecurityManager s = System.getSecurityManager();
+ _threadGroup = (s != null) ? s.getThreadGroup() : Thread
+ .currentThread().getThreadGroup();
+ }
+
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread thread = new Thread(_threadGroup, r,
+ "MetaModel.SharedExecutorService.Thread."
+ + counter.incrementAndGet());
+ thread.setDaemon(true);
+ thread.setPriority(Thread.NORM_PRIORITY);
+ return thread;
+ }
+ }
+
+ private static final ExecutorService executor = Executors
+ .newCachedThreadPool(new ThreadFactoryImpl());
+
+ private SharedExecutorService() {
+ // prevent instantiation
+ }
+
+ /**
+ * Gets the shared {@link ExecutorService}.
+ *
+ * @return an {@link ExecutorService} for shared usage.
+ */
+ public static final ExecutorService get() {
+ return executor;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/core/src/main/java/org/apache/metamodel/util/SimpleTableDef.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/util/SimpleTableDef.java b/core/src/main/java/org/apache/metamodel/util/SimpleTableDef.java
new file mode 100644
index 0000000..1739e95
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/util/SimpleTableDef.java
@@ -0,0 +1,203 @@
+/**
+ * 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.eobjects.metamodel.util;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+import org.eobjects.metamodel.DataContext;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.ColumnType;
+import org.eobjects.metamodel.schema.MutableColumn;
+import org.eobjects.metamodel.schema.MutableTable;
+import org.eobjects.metamodel.schema.Table;
+import org.eobjects.metamodel.schema.TableType;
+
+/**
+ * Represents a table definition to be used in scenarios where a
+ * {@link DataContext} is unable to detect/discover the table structure and
+ * needs some basic input around expected table structures.
+ *
+ * @author Kasper Sørensen
+ */
+public class SimpleTableDef implements Serializable, HasName {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String _name;
+ private final String[] _columnNames;
+ private final ColumnType[] _columnTypes;
+
+ /**
+ * Constructs a {@link SimpleTableDef} using a {@link Table} as a prototype.
+ *
+ * @param table
+ */
+ public SimpleTableDef(Table table) {
+ _name = table.getName();
+ _columnNames = new String[table.getColumnCount()];
+ _columnTypes = new ColumnType[table.getColumnCount()];
+ for (int i = 0; i < table.getColumnCount(); i++) {
+ Column column = table.getColumn(i);
+ _columnNames[i] = column.getName();
+ _columnTypes[i] = column.getType();
+ }
+ }
+
+ /**
+ * Constructs a {@link SimpleTableDef}.
+ *
+ * @param name
+ * the name of the table
+ * @param columnNames
+ * the names of the columns to include in the table
+ */
+ public SimpleTableDef(String name, String[] columnNames) {
+ this(name, columnNames, null);
+ }
+
+ /**
+ * Constructs a {@link SimpleTableDef}.
+ *
+ * @param name
+ * the name of table
+ * @param columnNames
+ * the names of the columns to include in the table
+ * @param columnTypes
+ * the column types of the columns specified.
+ */
+ public SimpleTableDef(String name, String[] columnNames, ColumnType[] columnTypes) {
+ _name = name;
+ _columnNames = columnNames;
+ if (columnTypes == null) {
+ columnTypes = new ColumnType[columnNames.length];
+ for (int i = 0; i < columnTypes.length; i++) {
+ columnTypes[i] = ColumnType.VARCHAR;
+ }
+ } else {
+ if (columnNames.length != columnTypes.length) {
+ throw new IllegalArgumentException(
+ "Property names and column types cannot have different lengths (found " + columnNames.length
+ + " and " + columnTypes.length + ")");
+ }
+ }
+ _columnTypes = columnTypes;
+ }
+
+ /**
+ * Gets the name of the table
+ *
+ * @return the name of the table
+ */
+ public String getName() {
+ return _name;
+ }
+
+ /**
+ * Gets the names of the columns in the table
+ *
+ * @return the names of the columns in the table
+ */
+ public String[] getColumnNames() {
+ return _columnNames;
+ }
+
+ /**
+ * Gets the types of the columns in the table
+ *
+ * @return the types of the columns in the table
+ */
+ public ColumnType[] getColumnTypes() {
+ return _columnTypes;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((_name == null) ? 0 : _name.hashCode());
+ result = prime * result + Arrays.hashCode(_columnTypes);
+ result = prime * result + Arrays.hashCode(_columnNames);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SimpleTableDef other = (SimpleTableDef) obj;
+ if (_name == null) {
+ if (other._name != null)
+ return false;
+ } else if (!_name.equals(other._name))
+ return false;
+ if (!Arrays.equals(_columnTypes, other._columnTypes))
+ return false;
+ if (!Arrays.equals(_columnNames, other._columnNames))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "SimpleDbTableDef[name=" + _name + ",columnNames=" + Arrays.toString(_columnNames) + ",columnTypes="
+ + Arrays.toString(_columnTypes) + "]";
+ }
+
+ /**
+ * Creates a {@link MutableTable} based on this {@link SimpleTableDef}. Note
+ * that the created table will not have any schema set.
+ *
+ * @return a table representation of this table definition.
+ */
+ public MutableTable toTable() {
+ String name = getName();
+ String[] columnNames = getColumnNames();
+ ColumnType[] columnTypes = getColumnTypes();
+
+ MutableTable table = new MutableTable(name, TableType.TABLE);
+
+ for (int i = 0; i < columnNames.length; i++) {
+ table.addColumn(new MutableColumn(columnNames[i], columnTypes[i], table, i, true));
+ }
+ return table;
+ }
+
+ /**
+ * Gets the index of a column name, or -1 if the column name does not exist
+ *
+ * @param columnName
+ * @return
+ */
+ public int indexOf(String columnName) {
+ if (columnName == null) {
+ throw new IllegalArgumentException("Column name cannot be null");
+ }
+ for (int i = 0; i < _columnNames.length; i++) {
+ if (columnName.equals(_columnNames[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+}