Java tutorial
/* * Copyright (C) 2013 The Java Storage project * Gelin Luo <greenlaw110(at)gmail.com> * * 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.osgl.storage.impl; import org.apache.commons.codec.Charsets; import org.osgl._; import org.osgl.exception.UnexpectedIOException; import org.osgl.storage.ISObject; import org.osgl.storage.IStorageService; import org.osgl.util.C; import org.osgl.util.E; import org.osgl.util.IO; import org.osgl.util.S; import javax.activation.MimetypesFileTypeMap; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; /** * The implementation of {@link ISObject} */ public abstract class SObject implements ISObject { private String key; private Map<String, String> attrs = new HashMap<String, String>(); private boolean valid = true; private Throwable cause = null; SObject(String key) { if (null == key) { throw new NullPointerException(); } this.key = key; } public static SObject getInvalidObject(String key, Throwable cause) { SObject sobj = of(key, ""); sobj.valid = false; sobj.cause = cause; return sobj; } public static ISObject getDumpObject(String key) { return of(key, ""); } public static ISObject getDumpObject(String key, Map<String, String> attrs) { SObject sobj = of(key, ""); sobj.setAttrs(attrs); return sobj; } public String getKey() { return key; } protected void setAttrs(Map<String, String> attrs) { if (null == attrs) return; this.attrs.putAll(attrs); } @Override public String getAttribute(String key) { return attrs.get(key); } @Override public ISObject setAttribute(String key, String val) { attrs.put(key, val); return this; } @Override public ISObject setAttributes(Map<String, String> attrs) { setAttrs(attrs); return this; } @Override public boolean hasAttribute() { return !attrs.isEmpty(); } @Override public Map<String, String> getAttributes() { return C.newMap(attrs); } @Override public boolean isEmpty() { String s = asString(); return null == s || "".equals(s); } @Override public boolean isValid() { return valid; } @Override public Throwable getException() { return cause; } @Override public void consumeOnce(_.Function<InputStream, ?> consumer) { InputStream is = null; try { is = asInputStream(); consumer.apply(is); } finally { IO.close(is); } } /** * Construct an SObject with file specified. The key to the * sobject is the file's path * @param file * @return an SObject */ public static SObject of(File file) { return of(file.getPath(), file); } /** * Construct an SObject with key and file specified * @see #of(String, java.io.File, java.util.Map) */ public static SObject of(String key, File file) { if (file.canRead() && file.isFile()) { SObject sobj = new FileSObject(key, file); sobj.setAttribute(ATTR_FILE_NAME, file.getName()); sobj.setAttribute(ATTR_CONTENT_TYPE, new MimetypesFileTypeMap().getContentType(file)); return sobj; } else { return getInvalidObject(key, new IOException("File is a directory or not readable")); } } /** * Deprecated * @see #of(String, java.io.File) */ @Deprecated public static SObject valueOf(String key, File f) { return of(key, f); } /** * Construct an SObject with specified key, file and attributes * specified in {@link java.util.Map} * @see #of(String, java.io.File, String...) */ public static SObject of(String key, File file, Map<String, String> attributes) { SObject sobj = of(key, file); sobj.setAttributes(attributes); return sobj; } /** * @see #of(String, java.io.File, java.util.Map) */ @Deprecated public static SObject valueOf(String key, File file, Map<String, String> conf) { return of(key, file, conf); } /** * Construct an SObject with key, file and attributes specified in * key1, val1, key2, val2... sequence * @see #of(String, java.io.File, java.util.Map) */ public static SObject of(String key, File file, String... attrs) { SObject sobj = of(key, file); Map<String, String> map = C.map(attrs); sobj.setAttributes(map); return sobj; } /** * Deprecated * @see #of(String, java.io.File, String...) */ @Deprecated public static SObject valueOf(String key, File file, String... attrs) { return of(key, file, attrs); } /** * Construct an sobject with specified input stream and a randomly * generated key. * * <p>Node the sobject constrcuted from input stream has limits * please see the comment to {@link #of(String, java.io.InputStream)} * </p> * * @see #of(String, java.io.InputStream) */ public static SObject of(InputStream is) { return of(S.random(), is); } /** * Construct an SObject with key and input stream. Note unlike sobject * constructed with String, byte array or file, the sobject constructed * with input stream can only be read for one time. If the program * tries to access the Sobject the second time, it will encountered an * {@link UnexpectedIOException}. Another limit of this sobject is it * does not support {@link org.osgl.storage.ISObject#getLength()} method * * <p>If it needs to construct an SObject without these limits from * an input stream, then it shall first read the inputstream into * a bytearray, and use the byte array to construct the sobject like * following code</p> * * <pre><code> * InputStream is = ... * ... * ISObject sobj = SObject.of(IO.readContent(is)) * </code><pre> */ public static SObject of(String key, InputStream is) { try { return new InputStreamSObject(key, is); } catch (Exception e) { return getInvalidObject(key, e); } } /** * deprecated * @see #of(String, java.io.InputStream) */ @Deprecated public static SObject valueOf(String key, InputStream is) { return of(key, is); } /** * Construct a sobject with key, input stream and attributes specified in a * {@link java.util.Map}. * * <p>Node the sobject constrcuted from input stream has limits * please see the comment to {@link #of(String, java.io.InputStream)} * </p> * * @see #of(String, java.io.InputStream) */ public static SObject of(String key, InputStream is, Map<String, String> conf) { SObject sobj = of(key, is); sobj.setAttributes(conf); return sobj; } /** * deprecated * @see #of(String, java.io.InputStream, java.util.Map) */ @Deprecated public static SObject valueOf(String key, InputStream is, Map<String, String> conf) { return of(key, is, conf); } /** * Construct a sobject with key, input stream and attributes specified in a * sequence like key1, val1, key2, val2, ... * * <p>Node the sobject constrcuted from input stream has limits * please see the comment to {@link #of(String, java.io.InputStream)} * </p> * * @see #of(String, java.io.InputStream) */ public static SObject of(String key, InputStream is, String... attrs) { SObject sobj = of(key, is); Map<String, String> map = C.map(attrs); sobj.setAttributes(map); return sobj; } /** * deprecated * @see #of(String, java.io.File, String...) */ @Deprecated public static SObject valueOf(String key, InputStream is, String... attrs) { return of(key, is, attrs); } /** * Construct an sobject with specified content in String and a randomly * generated key * * @see #of(String, String) */ public static SObject of(String content) { return new StringSObject(S.random(), content); } /** * Construct an sobject with content and key specified * * @see #of(String, String, Map) */ public static SObject of(String key, String content) { return new StringSObject(key, content); } /** * Deprecated * @see #of(String, String) */ @Deprecated public static SObject valueOf(String key, String content) { return of(key, content); } /** * Construct an sobject with content, key and attributes specified in * {@link java.util.Map} */ public static SObject of(String key, String content, Map<String, String> attrs) { SObject sobj = of(key, content); sobj.setAttributes(attrs); return sobj; } /** * Deprecated * @see #of(String, String, java.util.Map) */ @Deprecated public static SObject valueOf(String key, String content, Map<String, String> attrs) { return of(key, content, attrs); } /** * Construct an sobject with key, content and attributes specified in sequence * key1, val1, key2, val2, ... * * @see #of(String, String, java.util.Map) */ public static SObject of(String key, String content, String... attrs) { SObject sobj = of(key, content); Map<String, String> map = C.map(attrs); sobj.setAttributes(map); return sobj; } /** * Deprecated * @see #of(String, String, String...) */ @Deprecated public static SObject valueOf(String key, String content, String... attrs) { return of(key, content, attrs); } /** * Construct an sobject with content in byte array and * a random generated key * * @see #of(String, byte[]) */ public static SObject of(byte[] buf) { return of(S.random(), buf); } /** * Construct an sobject with specified key and content * in byte array * @see #of(String, byte[], java.util.Map) */ public static SObject of(String key, byte[] buf) { return new ByteArraySObject(key, buf); } /** * Deprecated * @see #of(String, byte[]) */ @Deprecated public static SObject valueOf(String key, byte[] buf) { return of(key, buf); } /** * Construct an sobject with specified key, content as byte array * and attributes in {@link java.util.Map} * * @see #of(String, byte[], String...) */ public static SObject of(String key, byte[] buf, Map<String, String> attrs) { SObject sobj = valueOf(key, buf); sobj.setAttributes(attrs); return sobj; } /** * Deprecated * @see #of(String, byte[], java.util.Map) */ @Deprecated public static SObject valueOf(String key, byte[] buf, Map<String, String> attrs) { return of(key, buf, attrs); } /** * Construct an sobject with specified key, content in byte array and * attributes in sequence of key1, val1, key1, val2, ... * @see #of(String, byte[], java.util.Map) */ public static SObject of(String key, byte[] buf, String... attrs) { SObject sobj = valueOf(key, buf); Map<String, String> map = C.map(attrs); sobj.setAttributes(map); return sobj; } /** * Deprecated * @see #of(String, byte[], String...) */ @Deprecated public static SObject valueOf(String key, byte[] buf, String... attrs) { return of(key, buf, attrs); } public static SObject valueOf(String key, ISObject copy) { SObject sobj = of(key, copy.asByteArray()); sobj.setAttrs(copy.getAttributes()); return sobj; } public static SObject lazyLoad(String key, IStorageService ss) { return new LazyLoadSObject(key, ss); } public static SObject lazyLoad(String key, IStorageService ss, Map<String, String> conf) { SObject sobj = lazyLoad(key, ss); sobj.setAttributes(conf); return sobj; } public static SObject lazyLoad(String key, IStorageService ss, String... attrs) { SObject sobj = lazyLoad(key, ss); Map<String, String> map = C.map(attrs); sobj.setAttributes(map); return sobj; } private static File createTempFile() { try { return File.createTempFile("sobj_", ".tmp"); } catch (IOException e) { throw E.ioException(e); } } private static class StringSObject extends SObject { private String s_ = null; StringSObject(String key, String s) { super(key); s_ = null == s ? "" : s; } @Override public byte[] asByteArray() { return s_.getBytes(); } @Override public File asFile() { File tmpFile = createTempFile(); IO.writeContent(s_, tmpFile); return tmpFile; } @Override public InputStream asInputStream() { return IO.is(asByteArray()); } @Override public String asString() { return s_; } @Override public String asString(Charset charset) throws UnexpectedIOException { return s_; } @Override public long getLength() { return s_.length(); } } private static class FileSObject extends SObject { private File file_; private byte[] ba_; FileSObject(String key, File file) { super(key); E.NPE(file); file_ = file; } private void readToCache() { if (null != ba_) return; ba_ = IO.readContent(file_); } @Override public long getLength() { return file_.length(); } @Override public File asFile() throws UnexpectedIOException { return file_; } @Override public String asString() throws UnexpectedIOException { return asString(Charsets.UTF_8); } @Override public String asString(Charset charset) throws UnexpectedIOException { readToCache(); return new String(ba_, charset); } @Override public byte[] asByteArray() throws UnexpectedIOException { readToCache(); return ba_; } @Override public InputStream asInputStream() throws UnexpectedIOException { return IO.is(file_); } } private static class ByteArraySObject extends SObject { protected byte[] buf_; ByteArraySObject(String key, byte[] buf) { super(key); E.NPE(buf); buf_ = buf; } @Override public byte[] asByteArray() { int len = buf_.length; byte[] ba = new byte[len]; System.arraycopy(buf_, 0, ba, 0, len); return ba; } @Override public File asFile() { File tmpFile = createTempFile(); IO.write(buf_, tmpFile); return tmpFile; } @Override public InputStream asInputStream() { return IO.is(buf_); } @Override public String asString() { return asString(Charsets.UTF_8); } @Override public String asString(Charset charset) throws UnexpectedIOException { return new String(buf_, charset); } @Override public long getLength() { return buf_.length; } } private static class InputStreamSObject extends SObject { private final InputStream is_; InputStreamSObject(String key, InputStream is) { super(key); E.NPE(is); this.is_ = is; } @Override public byte[] asByteArray() { return IO.readContent(is_); } @Override public File asFile() { File tmpFile = createTempFile(); IO.write(is_, tmpFile); return tmpFile; } @Override public InputStream asInputStream() { return is_; } @Override public String asString() { return asString(Charsets.UTF_8); } @Override public String asString(Charset charset) throws UnexpectedIOException { return new String(asByteArray(), charset); } @Override public long getLength() { throw E.unsupport(); } } private static class LazyLoadSObject extends SObject { private volatile ISObject sobj_; private IStorageService ss_; LazyLoadSObject(String key, IStorageService ss) { super(key); E.NPE(ss); ss_ = ss; } private ISObject force() { if (null == sobj_) { synchronized (this) { if (null == sobj_) sobj_ = ss_.get(getKey()); } } return sobj_; } @Override public long getLength() { return null == sobj_ ? -1 : sobj_.getLength(); } @Override public File asFile() throws UnexpectedIOException { return force().asFile(); } @Override public String asString() throws UnexpectedIOException { return force().asString(); } @Override public String asString(Charset charset) throws UnexpectedIOException { return force().asString(charset); } @Override public byte[] asByteArray() throws UnexpectedIOException { return force().asByteArray(); } @Override public InputStream asInputStream() throws UnexpectedIOException { return force().asInputStream(); } } }