All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osgl.storage.impl.SObject Maven / Gradle / Ivy

Go to download

A simple storage service supports plugin varieties of implementations including Amazon S3

There is a newer version: 1.11.1
Show newest version
/* 
 * Copyright (C) 2013 The Java Storage project
 * Gelin Luo 
 *
 * 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;

/*-
 * #%L
 * Java Storage Service
 * %%
 * Copyright (C) 2013 - 2017 OSGL (Open Source General Library)
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

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.storage.util.MimeTypes;
import org.osgl.util.*;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
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 attrs = new HashMap<>();
    protected boolean valid = true;
    protected Throwable cause = null;

    SObject(String key) {
        if (null == key) {
            throw new NullPointerException();
        }
        this.key = key;
    }

    @Override
    public boolean isDumb() {
        return false;
    }

    public static SObject getInvalidObject(String key, Throwable cause) {
        SObject sobj = of(key, "");
        sobj.valid = false;
        sobj.cause = cause;
        return sobj;
    }

    public String getKey() {
        return key;
    }

    protected void setAttrs(Map attrs) {
        if (null == attrs) return;
        this.attrs.putAll(attrs);
    }

    @Override
    public String getUrl() {
        return attrs.get(ATTR_URL);
    }

    @Override
    public String getFilename() {
        return getAttribute(ATTR_FILE_NAME);
    }

    @Override
    public String getContentType() {
        return getAttribute(ATTR_CONTENT_TYPE);
    }

    @Override
    public void setFilename(String filename) {
        E.illegalArgumentIf(S.blank(filename));
        setAttribute(ATTR_FILE_NAME, filename);
    }

    @Override
    public void setContentType(String contentType) {
        E.illegalArgumentIf(S.blank(contentType));
        setAttribute(ATTR_CONTENT_TYPE, contentType);
    }

    @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 attrs) {
        setAttrs(attrs);
        return this;
    }

    @Override
    public boolean hasAttribute() {
        return !attrs.isEmpty();
    }

    @Override
    public Map 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 consumer) {
        InputStream is = null;
        try {
            is = asInputStream();
            consumer.apply(is);
        } finally {
            IO.close(is);
        }
    }

    protected final String suffix() {
        String originalFilename = getAttribute(ATTR_FILE_NAME);
        if (S.notBlank(originalFilename)) {
            int pos = originalFilename.lastIndexOf(".");
            if (pos > -1) {
                return originalFilename.substring(pos, originalFilename.length());
            }
        }
        return "";
    }

    /**
     * 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, MimeTypes.mimeType(file));
            sobj.setAttribute(ATTR_CONTENT_LENGTH, S.string(file.length()));
            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 attributes) {
        SObject sobj = of(key, $.notNull(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 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, $.notNull(file));
        Map 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.
     * 

*

Node the sobject constrcuted from input stream has limits * please see the comment to {@link #of(String, java.io.InputStream)} *

* * @see #of(String, java.io.InputStream) */ public static SObject of(InputStream is) { return of(randomKey(), $.notNull(is)); } /** * Load an sobject from classpath by given url path * * This method will call {@link Class#getResource(String)} method to open * an inputstream to the resource and then construct an SObject with the * inputstream * * @param url the resource url path * @return the sobject instance if loaded successfully or `null` if cannot load resource from the url */ public static SObject loadResource(String url) { InputStream is = SObject.class.getResourceAsStream(url); if (null == is) { return null; } String filename = S.afterLast(url, "/"); if (S.blank(filename)) { filename = url; } return of(randomKey(), is, ATTR_FILE_NAME, filename); } /** * 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 *

*

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

*

*


     * InputStream is = ...
     * ...
     * ISObject sobj = SObject.of(IO.readContent(is))
     * 
     */
    public static SObject of(String key, InputStream is) {
        try {
            return new InputStreamSObject(key, $.notNull(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}.
     * 

*

Node the sobject constrcuted from input stream has limits * please see the comment to {@link #of(String, java.io.InputStream)} *

* * @see #of(String, java.io.InputStream) */ public static SObject of(String key, InputStream is, Map 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 conf) { return of(key, is, conf); } /** * Construct a sobject with key, input stream and attributes specified in a * sequence like key1, val1, key2, val2, ... *

*

Node the sobject constrcuted from input stream has limits * please see the comment to {@link #of(String, java.io.InputStream)} *

* * @see #of(String, java.io.InputStream) */ public static SObject of(String key, InputStream is, String... attrs) { SObject sobj = of(key, is); Map 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(randomKey(), 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, $.notNull(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 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 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 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(randomKey(), $.notNull(buf)); } /** * Construct an sobject with specified key and byte array. * * Note the byte array will be used directly without copying into an new array. * * @see #of(String, byte[], java.util.Map) */ public static SObject of(String key, byte[] buf) { return new ByteArraySObject(key, $.notNull(buf)); } /** * Construct an SObject with random generated key, byte array and number of bytes * @param buf the source byte array * @param len the number of bytes in the array should be stored in the returing object * @return an SObject as described above */ public static SObject of(byte[] buf, int len) { return of(randomKey(), buf, len); } /** * Construct an SObject with specified key, byte array and number of bytes * @param key the key * @param buf the source byte array * @param len the number of bytes in the array should be stored in the returing object * @return an SObject as described above */ public static SObject of(String key, byte[] buf, int len) { if (len <= 0) { return of(key, new byte[0]); } if (len >= buf.length) { return of(key, buf); } byte[] ba = new byte[len]; System.arraycopy(buf, 0, ba, 0, len); return of(key, ba); } /** * 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 attrs) { SObject sobj = of(key, $.notNull(buf)); sobj.setAttributes(attrs); return sobj; } /** * Deprecated * * @see #of(String, byte[], java.util.Map) */ @Deprecated public static SObject valueOf(String key, byte[] buf, Map 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 = of(key, $.notNull(buf)); Map 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 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 map = C.map(attrs); sobj.setAttributes(map); return sobj; } private static File createTempFile(String suffix) { try { return File.createTempFile("sobj_", suffix); } catch (IOException e) { throw E.ioException(e); } } static class StringSObject extends SObject { private String s_ = null; private boolean dumb = false; 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(suffix()); 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(); } @Override public boolean isDumb() { return dumb; } @Override public int hashCode() { return $.hc(getKey()); } @Override public String toString() { return s_; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof SObject) { SObject that = (SObject) obj; return $.eq(that.getKey(), getKey()) && $.eq(that.asString().toString(), toString()); } return false; } } static class FileSObject extends SObject { private File file_; private SoftReference cache; FileSObject(String key, File file) { super(key); E.NPE(file); file_ = file; } private synchronized byte[] read() { if (null != cache) { byte[] ba = cache.get(); if (null != ba) return ba; } byte[] ba = IO.readContent(file_); cache = new SoftReference(ba); return ba; } @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 { return new String(read(), charset); } @Override public byte[] asByteArray() throws UnexpectedIOException { return read(); } @Override public InputStream asInputStream() throws UnexpectedIOException { return IO.is(file_); } } 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(suffix()); 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; } } 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(suffix()); 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(); } } 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(); } } private static String randomKey() { return Codec.encodeUrl(S.random()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy