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;
+    }
+}