org.bibalex.gallery.model.BAGGalleryAbstract.java Source code

Java tutorial

Introduction

Here is the source code for org.bibalex.gallery.model.BAGGalleryAbstract.java

Source

//   Copyright 2013 Bibliotheca Alexandrina, Wellcome Trust 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.

package org.bibalex.gallery.model;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileType;
import org.apache.commons.vfs.VFS;
import org.apache.log4j.Logger;
import org.bibalex.gallery.exception.BAGAlbumAlreadyExistsException;
import org.bibalex.gallery.exception.BAGException;
import org.bibalex.gallery.exception.BAGNotFoundException;
import org.bibalex.gallery.storage.BAGStorage;
import org.bibalex.util.URLPathStrUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;

public abstract class BAGGalleryAbstract {
    public enum EnumResolutions {
        thumb, /* low, med, */high
    }

    // Too much caching could kill you!! Concurrency Issues.. and Djatoka already has a tiles cache anyway
    // protected static final Map<String, byte[]> imageBytesCache = Collections
    // .synchronizedMap(new WeakHashMap<String, byte[]>());;

    public static final String CONFIG_URL_ORDER_RESALBUM = "ResAlbum";

    public static final String CONFIG_URL_ORDER_ALBUMRES = "AlbumRes";
    public static final String CONFIG_URL_ORDER_DEFAULT = CONFIG_URL_ORDER_RESALBUM;
    public static final String FILENAME_GALLERY_METADATA_XML = "metagallery.xml";

    private static final Logger LOG = Logger.getLogger("org.bibalex.gallery");

    // gallery Root => http access gallery Direct => direct access
    // TODO rename
    protected final String galleryRoot;
    protected final String galleryDirect;

    protected final String configUrlOrder;

    protected final String cacheLocalPath;

    protected final String contextRootPath;

    protected final String metaGalleryRoot;

    protected final String djatokaServerUrlStr;

    // protected final int CONFIG_HTTPACC_PORT;

    // Too much caching could kill you!! Concurrency Issues!
    // protected static Map<String, BAGGalleryAbstract> instances = Collections
    // .synchronizedMap(new WeakHashMap<String, BAGGalleryAbstract>());
    //
    // public static BAGGalleryAbstract getInstance(String galleryRoot, String galleryDirect,
    // String configUrlOrder,
    // String cacheLocalPath,
    // String contextRootPath, String metaGalleryRoot, String djatokaServerUrlStr,
    // /* int galleryHttpAccPort, */
    // IBAGGalleryFactory factory) {
    // // TODO Revisit and correct the problem of sharing the same gallery between users while the metagallery
    // // is stored in the WC copy of each of them.. it uses the first
    // return factory
    // .construct(galleryRoot, galleryDirect, configUrlOrder,
    // cacheLocalPath,
    // contextRootPath, metaGalleryRoot,
    // djatokaServerUrlStr/* , galleryHttpAccPort */);
    // // synchronized (instances) {
    // // String key = galleryRoot + galleryDirect + configUrlOrder + cacheLocalPath
    // // + contextRootPath
    // // + metaGalleryRoot + djatokaServerUrlStr;
    // // if (!instances.containsKey(key)) {
    // // instances
    // // .put(key,
    // // factory
    // // .construct(galleryRoot, galleryDirect, configUrlOrder,
    // // cacheLocalPath,
    // // contextRootPath, metaGalleryRoot,
    // // djatokaServerUrlStr/* , galleryHttpAccPort */));
    // // }
    // //
    // // return instances.get(key);
    // // }
    // }

    private Document tempXml;

    protected BAGGalleryAbstract(String galleryRoot, String galleryDirect, String configUrlOrder,
            String cacheLocalPath, String contextRootPath, String metaGalleryRoot, String djatokaServerUrlStr
    /* int galleryHttpAccPort */) {
        super();

        this.galleryRoot = galleryRoot;
        this.galleryDirect = galleryDirect;
        this.configUrlOrder = configUrlOrder;
        this.cacheLocalPath = cacheLocalPath;
        this.contextRootPath = contextRootPath;
        this.metaGalleryRoot = metaGalleryRoot;
        this.djatokaServerUrlStr = djatokaServerUrlStr;
        // this.CONFIG_HTTPACC_PORT = galleryHttpAccPort;
    }

    public void addAlbumToMetaGallery(String albumName, String albumCaption, String coverName, String metaFileName)
            throws BAGException {
        try {
            Document metaDataXml = this.getMetaDataXml();

            XPath albumExistCheckXP;

            albumExistCheckXP = XPath.newInstance("//album[@name=$VARNAME]");
            albumExistCheckXP.setVariable("VARNAME", albumName);

            if (albumExistCheckXP.selectNodes(metaDataXml).size() > 0) {
                throw new BAGAlbumAlreadyExistsException("Album already exists in metadata file: " + albumName);
            }

            Element galleryElt = metaDataXml.getRootElement();

            Element albumElt = new Element("album");
            albumElt.setAttribute("name", albumName);

            galleryElt.addContent(albumElt);

            Element coverElt = new Element("cover");
            coverElt.setText(coverName);

            albumElt.addContent(coverElt);

            Element captionElt = new Element("caption");
            captionElt.setText(albumCaption);

            albumElt.addContent(captionElt);

            Element metadataElt = new Element("metadata");
            metadataElt.setText(metaFileName);

            albumElt.addContent(metadataElt);

            // ////////////////
            this.persistMetaGallery(metaDataXml);
        } catch (JDOMException e) {
            throw new BAGException(e);
        }

    }

    protected ArrayList<BAGThumbnail> createAlbumCoversFromXML(Document metaDataXml) throws BAGException {
        try {
            ArrayList<BAGThumbnail> result = new ArrayList<BAGThumbnail>();

            XPath albumsXP = XPath.newInstance("//album");

            for (Object obj : albumsXP.selectNodes(metaDataXml)) {
                Element elt = (Element) obj;

                String name = elt.getAttributeValue("name");

                String title;

                Element optionalTitle = elt.getChild("caption");
                if (optionalTitle != null) {
                    title = optionalTitle.getTextNormalize();
                    if ((title == null) || title.isEmpty()) {
                        title = name;
                    }
                } else {
                    title = name;
                }

                String coverImgName = elt.getChild("cover").getTextNormalize();

                String coverImgLocalUrl;
                try {
                    coverImgLocalUrl = this.getThumbLocalUrl(name, coverImgName);
                } catch (BAGException e) {
                    LOG.error(e, e);
                    continue;
                }
                // this.getThumbLocalUrl(name, coverImgName);
                BAGThumbnail cover = new BAGThumbnail(name, title, coverImgLocalUrl);

                result.add(cover);
            }

            return result;
        } catch (JDOMException e) {
            throw new BAGException(e);
        }
    }

    protected HashMap<String, BAGThumbnail> createMetaDataToAlbumCoverMapFromXML(Document metaDataXml)
            throws BAGException {
        try {
            HashMap<String, BAGThumbnail> result = new HashMap<String, BAGThumbnail>();

            XPath albumsXP = XPath.newInstance("//album");

            for (Object obj : albumsXP.selectNodes(metaDataXml)) {
                Element elt = (Element) obj;

                String name = elt.getAttributeValue("name");

                String title;

                Element optionalTitle = elt.getChild("caption");
                if (optionalTitle != null) {
                    title = optionalTitle.getTextNormalize();
                    if ((title == null) || title.isEmpty()) {
                        title = name;
                    }
                } else {
                    title = name;
                }

                String coverImgName = elt.getChild("cover").getTextNormalize();

                String coverImgLocalUrl;
                try {
                    coverImgLocalUrl = this.getThumbLocalUrl(name, coverImgName);
                } catch (BAGException e) {
                    LOG.error(e, e);
                    continue;
                }
                // this.getThumbLocalUrl(name, coverImgName);
                BAGThumbnail cover = new BAGThumbnail(name, title, coverImgLocalUrl);

                String metaDataFileName = elt.getChild("metadata").getTextNormalize();

                result.put(metaDataFileName, cover);
            }

            return result;
        } catch (JDOMException e) {
            throw new BAGException(e);
        }
    }

    public String deleteAlbumForMetadataFile(String metaAlbumFileName) throws BAGException {

        Element albumElt = this.getAlbumEltForMetadataFile(metaAlbumFileName);

        String albumName = albumElt.getAttributeValue("name");

        Document metaGalleryXML = albumElt.getDocument();

        albumElt.detach();

        this.persistMetaGallery(metaGalleryXML);

        return albumName;
    }

    public void deleteAlbumFromMetaGallery(String albumName) throws BAGException {
        try {
            Document metaDataXml = this.getMetaDataXml();

            XPath albumExistCheckXP;

            albumExistCheckXP = XPath.newInstance("//album[@name=$VARNAME]");
            albumExistCheckXP.setVariable("VARNAME", albumName);

            for (Object obj : albumExistCheckXP.selectNodes(metaDataXml)) {
                ((Element) obj).detach();
            }
            // ////////////////
            this.persistMetaGallery(metaDataXml);
        } catch (JDOMException e) {
            throw new BAGException(e);
        }
    }

    public BAGThumbnail getAlbumCoverFromLoadedTempXml(String albumName) throws BAGException {
        if (this.tempXml == null) {
            throw new BAGException("Must load temp xml before callig getAlbumCover");
        }
        try {
            ArrayList<BAGThumbnail> result = new ArrayList<BAGThumbnail>();

            XPath albumXP = XPath.newInstance("//album[@name=$ALBUMNAME]");
            albumXP.setVariable("ALBUMNAME", albumName);
            Object obj = albumXP.selectSingleNode(this.tempXml);
            if (obj == null) {
                return null;
                // throw new BAGException("Album not found");
            }
            Element elt = (Element) obj;

            String title;

            Element optionalTitle = elt.getChild("caption");
            if (optionalTitle != null) {
                title = optionalTitle.getTextNormalize();
                if ((title == null) || title.isEmpty()) {
                    title = albumName;
                }
            } else {
                title = albumName;
            }

            String coverImgName = elt.getChild("cover").getTextNormalize();

            BAGThumbnail cover = new BAGThumbnail(albumName, title, coverImgName);

            return cover;
        } catch (JDOMException e) {
            throw new BAGException(e);
        }
    }

    public List<BAGThumbnail> getAlbumCovers() throws BAGException {
        Document metaDataXml = this.getMetaDataXml();
        return this.createAlbumCoversFromXML(metaDataXml);
    }

    protected String getAlbumDirectAccURLStr(String albumName, EnumResolutions res) {
        String result;

        result = URLPathStrUtils.appendParts(this.galleryDirect, this.orderUrlParts(res.toString(), albumName));

        return result;

    }

    private Element getAlbumEltForMetadataFile(String metaAlbumFileName) throws BAGException {
        try {
            Document metagallery = this.getMetaDataXml();

            XPath albumForMetadataFileXP;

            albumForMetadataFileXP = XPath.newInstance("//album[child::metadata = $VARMETAFN]");

            albumForMetadataFileXP.setVariable("VARMETAFN", metaAlbumFileName);

            List objs = albumForMetadataFileXP.selectNodes(metagallery);

            if (objs.size() == 0) {
                throw new BAGNotFoundException("Querying for the album of metadata file: " + metaAlbumFileName
                        + " shourld return one result but returned: " + objs.size());
            } else if (objs.size() > 1) {
                throw new BAGException("Querying for the album of metadata file: " + metaAlbumFileName
                        + " shourld return one result but returned: " + objs.size());
            }

            return ((Element) objs.get(0));
        } catch (JDOMException e) {
            throw new BAGException(e);
        }
    }

    protected String getAlbumHttpAccUrlStr(String albumName, EnumResolutions res) {
        String resHttpBase;

        resHttpBase = URLPathStrUtils.appendParts(this.galleryRoot, this.orderUrlParts(res.toString(), albumName));

        return resHttpBase;
    }

    protected ArrayList<String> getAlbumNamesFromXML(Document metaDataXml) throws BAGException {
        // TODO refactor so that the logic shared with createAlbumCo.. is DRY
        try {
            ArrayList<String> result = new ArrayList<String>();

            XPath albumsXP = XPath.newInstance("//album");

            for (Object obj : albumsXP.selectNodes(metaDataXml)) {
                Element elt = (Element) obj;

                String name = elt.getAttributeValue("name");

                String title;

                result.add(name);
            }

            return result;
        } catch (JDOMException e) {
            throw new BAGException(e);
        }
    }

    public List<String> getAllFolders() throws BAGException {
        String albumsFolderUrlStr = this.galleryRoot;

        if (CONFIG_URL_ORDER_RESALBUM.equals(this.configUrlOrder)) {
            albumsFolderUrlStr = URLPathStrUtils.appendParts(albumsFolderUrlStr, EnumResolutions.thumb.toString());
        } else {
            throw new UnsupportedOperationException("TODO");
        }

        return BAGStorage.listChildren(albumsFolderUrlStr, FileType.FOLDER);

        // public List<BAGThumbnail> getAllFolders() throws BAGException {
        //
        // ArrayList<BAGThumbnail> result = new ArrayList<BAGThumbnail>();
        // for (String albumName : BAGStorage.listChildren(albumsFolderUrlStr, FileType.FOLDER)) {
        // String albumThumbsUrlStr = this.getResolutionBaseURLStr(albumName,
        // EnumResolutions.thumb);
        // String firstThumbUrlStr = BAGStorage.listChildren(albumThumbsUrlStr, FileType.FILE).get(0);
        //
        // String firstThumbLocalUrl = this.getThumbLocalUrl(albumName, FilenameUtils
        // .removeExtension(firstThumbUrlStr));
        //
        // result.add(new BAGThumbnail(albumName, albumName, firstThumbLocalUrl));
        // }
        // return result;

    }

    public String getDjatokaServerUrlStr() {
        return this.djatokaServerUrlStr;
    }

    protected String getImageDirectAccUrlStr(String albumName, String imageName, EnumResolutions res) {

        String resDirectpBase = this.getAlbumDirectAccURLStr(albumName, res);

        return this.getImageUrlStr(resDirectpBase, imageName, res);

    }

    protected String getImageHttpAccUrlStr(String albumName, String imageName, EnumResolutions res)
            throws BAGException {

        String resHttpBase = this.getAlbumHttpAccUrlStr(albumName, res);

        return this.getImageUrlStr(resHttpBase, imageName, res);

    }

    private String getImageUrlStr(String albumBaseUrlStr, String imageName, EnumResolutions res) {
        String ext = null;
        switch (res) {
        case high:
            ext = ".jp2";
            break;
        case thumb:
            ext = ".jpg";
            break;

        }

        String imgUrlStr = URLPathStrUtils.appendParts(albumBaseUrlStr, imageName + ext);

        return imgUrlStr;
    }

    // public byte[] getImageBytes(String imageUrlStr) throws BAGException {
    // synchronized (imageBytesCache) {
    // if (!imageBytesCache.containsKey(imageUrlStr)) {
    // ByteArrayOutputStream cacheBytesOut = new ByteArrayOutputStream();
    // try {
    // BAGStorage.readRemoteFile(imageUrlStr, cacheBytesOut);
    // imageBytesCache.put(imageUrlStr, cacheBytesOut.toByteArray());
    // } finally {
    // try {
    // cacheBytesOut.close();
    // } catch (IOException e) {
    // throw new BAGException(e);
    // }
    // }
    // }
    //
    // return imageBytesCache.get(imageUrlStr);
    // }
    // }

    public Element getMetaAlbumEltForMetadataFile(String metaAlbumFileName) throws BAGException {
        return (Element) this.getAlbumEltForMetadataFile(metaAlbumFileName).clone();
    }

    public String getMetaAlbumStrForMetadataFile(String metaAlbumFileName) throws BAGException {
        try {
            Element albumElt = this.getAlbumEltForMetadataFile(metaAlbumFileName);

            XMLOutputter outputter = new XMLOutputter(Format.getCompactFormat().setEncoding("UTF-8"));

            StringWriter resultWriter = new StringWriter();

            outputter.output(albumElt, resultWriter);

            resultWriter.flush();
            resultWriter.close();

            String result = resultWriter.toString();

            return result;
        } catch (IOException e) {
            throw new BAGException(e);
        }

    }

    public HashMap<String, BAGThumbnail> getMetaDataToAlbumCoverMap() throws BAGException {
        Document metaDataXml = this.getMetaDataXml();
        return this.createMetaDataToAlbumCoverMapFromXML(metaDataXml);
    }

    protected abstract Document getMetaDataXml() throws BAGException;

    public String getMetaGalleryFileUrlStr() {
        return URLPathStrUtils.appendParts(this.metaGalleryRoot, FILENAME_GALLERY_METADATA_XML);
    }

    public List<String> getNonAlbumedFolders() throws BAGException {
        // public List<BAGThumbnail> getNonAlbumedFolders() throws BAGException {
        //
        // List<BAGThumbnail> result = this.getAllFolders();
        //
        // List<BAGThumbnail> albums = this.getAlbumCovers();

        List<String> result = this.getAllFolders();

        Document metaDataXml = this.getMetaDataXml();
        List<String> albums = this.getAlbumNamesFromXML(metaDataXml);

        result.removeAll(albums);

        // Iterator<String> candidatesIter = result.iterator();
        // while (candidatesIter.hasNext()) {
        //
        // // BAGThumbnail candidate = candidatesIter.next();
        // String candidate = candidatesIter.next();
        // if (albums.indexOf(candidate) != -1) {
        // candidatesIter.remove();
        // }
        //
        // }

        return result;
    }

    public String getThumbLocalUrl(String albumName, String imageName) throws BAGException {
        try {
            String thumbImgUrlStr = this.getImageHttpAccUrlStr(albumName, imageName, EnumResolutions.thumb);

            String cachedURLAbs = BAGStorage
                    .cacheFileLocally(URLPathStrUtils.appendParts(this.cacheLocalPath, "thumb", albumName),
                            thumbImgUrlStr)
                    .toString();

            String ctxRootURL = VFS.getManager().resolveFile(this.contextRootPath).getURL().toString();

            String result = cachedURLAbs.substring(ctxRootURL.length());

            return result;

        } catch (FileSystemException e) {
            throw new BAGException(e);
        }
    }

    public void loadTempXml() throws BAGException {
        if (this.tempXml != null) {
            throw new BAGException("Already loaded");
        }
        SAXBuilder saxBuilder = new SAXBuilder();

        saxBuilder.setFeature("http://xml.org/sax/features/validation", false);
        saxBuilder.setFeature("http://xml.org/sax/features/namespaces", true);
        saxBuilder.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
        // Unsupported: saxBuilder.setFeature("http://xml.org/sax/features/xmlns-uris", false);

        String metaDataUrl = this.getMetaGalleryFileUrlStr();
        // URLPathStrUtils.appendParts(this.metaGalleryRoot, FILENAME_GALLERY_METADATA_XML);

        try {
            ByteArrayOutputStream remoteFileOS = new ByteArrayOutputStream();
            ByteArrayInputStream metaGalleryIn = null;
            try {
                BAGStorage.readRemoteFile(metaDataUrl, remoteFileOS);

                metaGalleryIn = new ByteArrayInputStream(remoteFileOS.toByteArray());

                this.tempXml = saxBuilder.build(metaGalleryIn);

            } finally {
                try {
                    remoteFileOS.close();
                    metaGalleryIn.close();
                } catch (IOException e) {
                    throw new BAGException(e);
                }
            }

        } catch (JDOMException e) {
            throw new BAGException(e);
        } catch (IOException e) {
            throw new BAGException(e);
        }

    }

    public BAGAlbum openAlbum(String name) throws BAGException {

        return new BAGAlbum(this, name);

    }

    public BAGAlbum openAlbumForMetadataFile(String metaAlbumFileName) throws BAGException {

        String albumName = this.getAlbumEltForMetadataFile(metaAlbumFileName).getAttributeValue("name");

        return this.openAlbum(albumName);

    }

    protected String[] orderUrlParts(String resolution, String albumName) {
        if (CONFIG_URL_ORDER_RESALBUM.equals(this.configUrlOrder)) {
            return new String[] { resolution, albumName };
        } else if (CONFIG_URL_ORDER_ALBUMRES.equals(this.configUrlOrder)) {
            return new String[] { albumName, resolution };
        } else {
            throw new IllegalArgumentException(this.configUrlOrder); // config not argument
        }
    }

    protected void persistMetaGallery(Document metaDataXml) throws BAGException {
        try {
            String filePath = this.getMetaGalleryFileUrlStr();

            FileWriter writer = new FileWriter(filePath);

            XMLOutputter outputter = new XMLOutputter(Format.getCompactFormat().setEncoding("UTF-8"));
            outputter.output(metaDataXml, writer);
        } catch (IOException e) {
            throw new BAGException(e);
        }
    }

    public void unloadTempXml() {
        this.tempXml = null;
    }
}