org.iavante.sling.gad.content.impl.ContentToolsImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.iavante.sling.gad.content.impl.ContentToolsImpl.java

Source

/*
 * Digital Assets Management
 * =========================
 * 
 * Copyright 2009 Fundacin Iavante
 * 
 * Authors: 
 *   Francisco Jos Moreno Llorca <packo@assamita.net>
 *   Francisco Jess Gonzlez Mata <chuspb@gmail.com>
 *   Juan Antonio Guzmn Hidalgo <juan@guzmanhidalgo.com>
 *   Daniel de la Cuesta Navarrete <cues7a@gmail.com>
 *   Manuel Jos Cobo Fernndez <ranrrias@gmail.com>
 *
 * Licensed under the EUPL, Version 1.1 or  as soon they will be approved by
 * the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://ec.europa.eu/idabc/eupl
 *
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and 
 * limitations under the Licence.
 * 
 */
package org.iavante.sling.gad.content.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.NotActiveException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.jcr.AccessDeniedException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.binary.Base64;
import org.apache.sling.jcr.api.SlingRepository;

import org.iavante.sling.commons.distributionserver.IDistributionServer;
import org.iavante.sling.commons.services.DistributionServiceProvider;
import org.iavante.sling.commons.services.PortalSetup;
import org.iavante.sling.commons.services.GADContentCreationService;
import org.iavante.sling.commons.services.ServiceProvider;

import org.iavante.sling.gad.content.ContentTools;
import org.iavante.sling.gad.downloader.services.IDownloader;
import org.iavante.sling.s3backend.S3backend;
import org.iavante.sling.s3backend.S3BackendFactory;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @scr.component
 * @scr.property name="service.description" value="IAVANTE - Content Tools"
 * @scr.property name="service.vendor" value="IAVANTE Foundation"
 * @scr.service interface="org.iavante.sling.gad.content.ContentTools"
 */
public class ContentToolsImpl implements ContentTools, Serializable {
    private static final long serialVersionUID = 1L;

    /** Default Logger. */
    private final Logger log = LoggerFactory.getLogger(getClass());

    /** @scr.reference */
    private S3backend s3backend;

    /** @scr.reference */
    private S3BackendFactory s3_factory;

    /** @scr.reference */
    private ServiceProvider serviceProvider;

    /** @scr.reference */
    private PortalSetup portalSetup;

    /** @scr.reference */
    private SlingRepository repository;

    /** @scr.reference */
    private DistributionServiceProvider myDSProvider;

    /** @scr.reference */
    private GADContentCreationService content_creation;

    /** @scr.reference */
    private IDownloader downloader_tool;

    /** Sources folder. */
    private final String SOURCES_FOLDER = "sources";

    /** Source resource type */
    private final String SOURCE_RESOURCETYPE = "gad/source";

    /** Content resource type */
    private final String CONTENT_RESOURCETYPE = "gad/content";

    /** Revision resource type */
    private final String REVISION_RESOURCETYPE = "gad/revision";

    /** Resource type */
    private final String RESOURCETYPE = "sling:resourceType";

    /** Default source of a content. */
    private final String FUENTE_DEFAULT = "fuente_default";

    /** Prop for default subtitle in source. */
    private final String PROP_DEFAULT_SUBTITLE = "default_subtitle";

    /** Prop for default audiodescription in source. */
    private final String PROP_DEFAULT_AUDIODESCRIPTION = "default_audiodescription";

    /** File property. */
    private final String FILE_PROP = "file";

    /** The name of the schema file. */
    private final String SCHEMA_FILE = "schema.smil";

    /** Path to subtitle_default */
    private final String subTag = "sources/subtitle_default";

    /** Downloader url */
    private String downloader_url = "";

    /** Base repository dir */
    private String base_repo_dir = "";

    /** Core public url */
    private String public_url = "";

    /** Scape char **/
    private String url_scape_char = "aAa";

    /** Smil variables. */
    private String property_key_open = "{{";
    private String property_key_close = "}}";
    private String method_key_open = "[[";
    private String method_key_close = "]]";

    /** Mark for playlist in the schema. */
    private String method_playlist = "#@playlist@#";
    private String unknown_value = "Desconocido";

    /** JCR root node. */
    private Node rootNode;

    /** JCR Session. */
    private Session session;

    protected void activate(ComponentContext context) {
        this.downloader_url = portalSetup.get_config_properties("/downloader").get("url");
        this.public_url = portalSetup.get_config_properties("/sling").get("public_url");
        this.base_repo_dir = portalSetup.get_config_properties("/sling").get("base_repo_dir");

        try {
            session = repository.loginAdministrative(null);
            this.rootNode = session.getRootNode();
        } catch (Exception e) {
            log.error("cannot start");
        }
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String get_url(ServletRequest req, Node node) throws RepositoryException {
        return get_url(node);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.iavante.sling.gad.content.ContentTools#getExternalUrl(javax.jcr.Node,
     * java.lang.String)
     */
    public String getExternalUrl(Node node, String format) {

        try {
            if (log.isInfoEnabled())
                log.info("getExternalUrl, node: " + node.getPath() + ", format: " + format);
        } catch (Exception e) {
        }

        String url = "";
        if ("".equals(format)) {
            format = "preview";
        }

        // If the node is in collections or catalog we return the s3 url
        if (("collections".equals(get_node_space(node))) || "catalog".equals(get_node_space(node))) {
            return this.getS3Url(node);
        }

        // If the node is in channels we have to check the channel distribution
        // server and channel distribution server configuration
        else {
            try {
                if ((node.hasProperty("sling:resourceType"))
                        && (!"".equals(node.getProperty("sling:resourceType").getValue().getString()))) {

                    String resource_type = node.getProperty("sling:resourceType").getValue().getString();
                    Node channel = null;

                    if (REVISION_RESOURCETYPE.equals(resource_type)) {
                        channel = node.getParent().getParent();
                    }

                    else if (SOURCE_RESOURCETYPE.equals(resource_type)) {
                        channel = node.getParent().getParent().getParent().getParent();
                    }

                    String filename = content_creation.getFilenameFromNode(node, format);

                    if (log.isInfoEnabled())
                        log.info("getExternalUrl, channel:** " + channel.getPath() + ", filename: " + filename);

                    if ((channel.hasProperty("distribution_server"))
                            && (!"".equals(channel.getProperty("distribution_server").getValue().getString()))) {
                        String ds = channel.getProperty("distribution_server").getValue().getString();
                        if ("s3".equals(ds)) {

                            // Checks if the channel node has custom distribution server
                            // properties
                            // to instantiate the factory
                            if (!channel.hasNode("ds_custom_props")) {
                                try {
                                    url = s3backend.getUrl(filename);
                                    if (log.isInfoEnabled())
                                        log.info("getExternalUrl, url: " + url);
                                } catch (NotActiveException e) {
                                    e.printStackTrace();
                                }
                                return url;

                            }

                            Node custom_props = channel.getNode("ds_custom_props");
                            Map<String, String> prop_dict = new HashMap<String, String>();

                            if (custom_props.hasProperty("edited")) {
                                if (log.isInfoEnabled())
                                    log.info("getExternalUrl, Reading custom distribution server properties");
                                PropertyIterator props = custom_props.getProperties();

                                while (props.hasNext()) {
                                    Property prop = props.nextProperty();
                                    prop_dict.put(prop.getName(), prop.getValue().getString());
                                }

                                if (log.isInfoEnabled())
                                    log.info("getExternalUrl, Configuring s3 instance");

                                S3backend s3_backend = (S3backend) s3_factory.getService(prop_dict);
                                try {
                                    url = s3_backend.getUrl(filename);
                                } catch (NotActiveException e) {
                                    e.printStackTrace();
                                }
                                s3_backend = null;
                            } else {
                                try {
                                    url = s3backend.getUrl(filename);
                                    if (log.isInfoEnabled())
                                        log.info("getExternalUrl, url: " + url);
                                } catch (NotActiveException e) {
                                    e.printStackTrace();
                                }
                            }
                        }

                        // Static distribution server instantiation
                        else {
                            IDistributionServer myDServer = myDSProvider.get_distribution_server(ds);
                            try {
                                url = myDServer.getUrl(filename);
                            } catch (NotActiveException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            } catch (ValueFormatException e) {
                e.printStackTrace();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (PathNotFoundException e) {
                e.printStackTrace();
            } catch (RepositoryException e) {
                e.printStackTrace();
            }
        }
        return url;
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public Boolean isPlaylist(Node contentNode) {
        Boolean hasPlayList = false;

        try {
            Node a = contentNode;
            Property thisSchema = a.getProperty("schema");

            if (thisSchema.getValue().getString().equals("playlist")) {
                hasPlayList = true;
            }

            PropertyIterator b = a.getProperties();
            while (b.hasNext()) {
                Property d = b.nextProperty();
            }

        } catch (ItemNotFoundException e2) {
            e2.printStackTrace();
        } catch (AccessDeniedException e2) {
            e2.printStackTrace();
        } catch (RepositoryException e2) {
            e2.printStackTrace();
        }

        return hasPlayList;
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getS3Url(Node node) {
        String fileName = content_creation.getFilenameFromNode(node, "");

        try {
            return s3backend.getUrl(fileName);
        } catch (Exception e) {

            log.error("getS3Url,Error using S3 service");
            return "";
        }
    }

    /*
     * @see org.iavante.sling.gad.content.Content
     */
    public String getSmil(Node content, String storage) {

        String schema = getContentSchema(content);

        // first step, check if the schema is a playlist
        if (hasPlaylistMark(schema) == true)
            return getPlaylist(content, storage);

        // second step: replace the properties keys with the value of node
        schema = replaceWithNodeValues(content, schema);

        // third step: replace the methods calls with the return value
        schema = replaceWithReturnOfMethods(content, schema, storage);

        return schema;
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getSmil(Node content) {

        return getSmil(content, "external");
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getContentSchema(Node content) {

        String schema = null;
        try {

            if (content.getProperty("sling:resourceType").getString().compareTo("gad/content") != 0
                    && content.getProperty("sling:resourceType").getString().compareTo("gad/revision") != 0)
                return "";
            schema = content.getNode(SOURCES_FOLDER).getNode("schema.smil").getNode("jcr:content")
                    .getProperty("jcr:data").getString();
        } catch (ValueFormatException e) {
            log.error(e.toString());
        } catch (PathNotFoundException e) {
            log.error(e.toString());
        } catch (RepositoryException e) {
            log.error(e.toString());
        }
        return schema;
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getPlaylist(Node content) {
        return getPlaylist(content, "external");
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getPlaylist(Node content, String storage) {

        // get schema
        String schema = getContentSchema(content);

        // get media list
        List<String> lines = getPlaylistLines(content, storage);

        int b1 = schema.indexOf("<body>");
        int b2 = schema.indexOf("</body>");

        // replace the section <seq>...</seq> of the schema.smil
        schema = schema.substring(0, b1 + 6) + "\n\t<seq>"
                + lines.toString().substring(1, lines.toString().length() - 1).replace(">,", ">") + "\n\t</seq>\n"
                + schema.substring(b2, schema.length());

        schema = replaceWithNodeValues(content, schema);

        return schema;
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getXSPF(Node content, String storage) {

        String contentTitle = "";
        String contentOwner = "";
        String contentDescription = "";
        String contentVideoPreviewDefaultUrl = "";
        String contentThumbPreviewDefaultUrl = "";
        String contentSubtitleDefaultUrl = "";
        String contentCierrePreviewUrl = "";
        String S3Url = "";

        try {
            if (content.hasProperty("title")) {
                contentTitle = content.getProperty("title").getValue().getString();
            }

            if (content.hasProperty("description")) {
                contentDescription = content.getProperty("description").getValue().getString();
            }

            if (content.hasProperty("author")) {
                contentOwner = content.getProperty("author").getValue().getString();
            }
            contentThumbPreviewDefaultUrl = getThumbUrl(content);

            contentSubtitleDefaultUrl = getSubtitleUrl(content, null);

            contentVideoPreviewDefaultUrl = getExternalUrl(content, "");

        } catch (ValueFormatException e) {
            e.printStackTrace();
            return "Error getXSPF";
        } catch (IllegalStateException e) {
            e.printStackTrace();
            return "Error getXSPF";
        } catch (PathNotFoundException e) {
            e.printStackTrace();
            return "Error getXSPF";
        } catch (RepositoryException e) {
            e.printStackTrace();
            return "Error getXSPF";
        }

        String xspfstring = "";

        // Cabecera
        xspfstring += "<playlist version='1' xmlns='http://xspf.org/ns/0/' xmlns:jwplayer='http://developer.longtailvideo.com/trac/wiki/FlashFormats'>";

        // Titulo Generico
        xspfstring += "<title>" + contentTitle + "</title>";
        // Inicio del TrackList
        xspfstring += "<tracklist>";

        Map<String, String> mmassets = getMultimediaAssets(content);

        String tvicon = mmassets.get("tvicon");
        String ending = mmassets.get("ending");

        // Contenido Default
        xspfstring += "<track>" +

                "<title>" + contentTitle + "</title>" +

                "<creator>" + contentOwner + "</creator>" +

                "<annotation>" + contentDescription + "</annotation>" +

                "<location>" + contentVideoPreviewDefaultUrl + "</location>" +

                "<image>" + contentThumbPreviewDefaultUrl + "</image>";

        if (contentSubtitleDefaultUrl.equals("") || contentSubtitleDefaultUrl.equals(null)) {
            // her we can put a alternative subtitle if doesn't exist the default.
            // xspfstring+="<jwplayer:captions.file>"+"Ajuqueplan:"+""+"</jwplayer:captions.file>";

        } else {
            xspfstring += "<jwplayer:captions.file>" + contentSubtitleDefaultUrl + "</jwplayer:captions.file>";

        }
        xspfstring += "</track>";

        // Cierre de Canal

        if (!(ending == null)) {
            Node endingNode;
            try {
                endingNode = rootNode.getNode(ending.substring(1));
                S3Url = getS3Url(endingNode);
                xspfstring += "<track>" +

                        "<title>" + "Cierre de Canal" + "</title>" +

                        "<creator>" + "GAD Channel Settings" + "</creator>" +

                        "<annotation>" + "GAD Channel Settings" + "</annotation>" +

                        "<location>" + S3Url + "</location>" +

                        "</track>";

            }

            catch (PathNotFoundException e) {

                e.printStackTrace();
            } catch (RepositoryException e) {

                e.printStackTrace();
            }

        }

        // Fin del trackList

        xspfstring += "</tracklist>";

        // Fin del Playlist

        xspfstring += "</playlist>";

        return xspfstring;
    }

    /**
     * Returns playlist lines.
     * 
     * @param content
     *          the content node to check
     * @return a Boolean
     */
    public Boolean hasEndingVideo(Node content) {

        Map<String, String> ma = new HashMap<String, String>();
        NodeIterator it = null;
        boolean hasEndingVideo = false;
        boolean needEnding = false;

        try {
            // check if multimedia_assets are needed.
            if (content.getProperty("sling:resourceType").getValue().getString()
                    .compareToIgnoreCase("gad/revision") == 0) {
                if (content.hasProperty("needEnding")
                        && content.getProperty("needEnding").getValue().getString().compareToIgnoreCase("1") == 0) {
                    needEnding = true;
                }
            }
            if (needEnding && content.getPath().contains("canales")) {
                ma = getMultimediaAssets(content);
            }

            assert content.getProperty("sling:resourceType").getValue().getString()
                    .compareToIgnoreCase("gad/content") == 0;
            it = content.getNode(SOURCES_FOLDER).getNodes();

        } catch (RepositoryException e) {
            log.error("getPlaylistLines," + e.toString());
            e.printStackTrace();
        }

        try {

            boolean hasVideo = false;
            Node nod = null;
            while (it.hasNext()) {

                nod = it.nextNode();
                if (nod.hasProperty("sling:resourceType") && nod.getProperty("sling:resourceType").getString()
                        .compareToIgnoreCase("gad/source") == 0) {

                    // Check if has declared ending video
                    if (nod.getProperty("type").getString().contains("video")) {
                        hasVideo = true;
                    }

                }
            }

            // Checking if the ending video exists
            if (needEnding && hasVideo && ((String) ma.get("ending") != null)) {

                hasEndingVideo = true;
            }

        } catch (ValueFormatException e) {
            log.error(e.toString());
        } catch (PathNotFoundException e) {
            if (e.toString().compareToIgnoreCase("javax.jcr.PathNotFoundException: type") == 0)
                log.info("the source has no type and doesn't be included");
            else
                log.error(e.toString());
        } catch (RepositoryException e) {
            log.error(e.toString());
        }

        return hasEndingVideo;
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getEndingVideoUrl(Node content) {

        String ending = "";
        String url = "";

        Map<String, String> mmassets = getMultimediaAssets(content);
        ending = mmassets.get("ending");

        if (!(ending == null)) {
            Node endingNode = null;

            try {
                endingNode = rootNode.getNode(ending.substring(1));
                url = getS3Url(endingNode);
            } catch (PathNotFoundException e) {
                e.printStackTrace();
            } catch (RepositoryException e) {
                e.printStackTrace();
            }

            return url;
        } else {
            return null;
        }
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getThumbUrl(Node node) {

        String fileName = null;
        String format = "";

        // Checks if the path exists
        try {

            if (!node.hasNode(SOURCES_FOLDER + "/thumbnail_default" + "/transformations/image_preview")
                    && !node.hasNode(SOURCES_FOLDER + "/thumbnail_default" + "/transformations/preview")) {
                return "";
            }
        } catch (RepositoryException e1) {
            e1.printStackTrace();
        }

        try {

            String trans_path = "";

            if (node.hasNode(SOURCES_FOLDER + "/thumbnail_default" + "/transformations/image_preview")) {
                trans_path = "image_preview";
            } else if (node.hasNode(SOURCES_FOLDER + "/thumbnail_default" + "/transformations/preview")) {
                trans_path = "preview";
            }

            Node thumb_node = node.getNode(SOURCES_FOLDER).getNode("thumbnail_default").getNode("transformations")
                    .getNode(trans_path);
            fileName = content_creation.getFilenameFromNode(thumb_node, "");
        } catch (PathNotFoundException e) {
            e.printStackTrace();
        } catch (RepositoryException e) {
            e.printStackTrace();
        }

        try {
            return s3backend.getUrl(fileName);
        } catch (Exception e) {
            log.error("getThumbUrl, Error using S3 service");
            return "";
        }
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getThumbPreviewUrl(Node node, int previewNumber) {

        String fileName = null;

        // Checks if the path exists
        /*
         * try { if (!node.hasNode("transformations/image_preview_"+previewNumber))
         * { return "transformations/image_preview_ "; } } catch
         * (RepositoryException e1) { e1.printStackTrace(); }
         */
        try {
            Node thumb_node = node.getNode("transformations").getNode("thumbnail_preview_" + previewNumber);
            fileName = content_creation.getFilenameFromNode(thumb_node, "");

        } catch (PathNotFoundException e) {
            e.printStackTrace();
            return "";
        } catch (RepositoryException e) {
            e.printStackTrace();
            return "";
        }

        try {
            return s3backend.getUrl(fileName);
        } catch (Exception e) {
            return "";
        }
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getTviconUrl(Node content, String storage) {

        String tvicon = "";
        String url = "";
        String format = "image_preview";

        if (!"channels".equals(get_node_space(content))) {
            // TODO Return the default TV Icon
            return "";
        }

        Map<String, String> mmassets = getMultimediaAssets(content);
        tvicon = mmassets.get("tvicon");

        if (!(tvicon == null)) {
            Node tviconNode = null;

            try {
                tviconNode = rootNode.getNode(tvicon.substring(1));
                if ("internal".equals(storage)) {
                    String fileName = content_creation.getFilenameFromNode(tviconNode, format);
                    url = downloader_tool.getUrl(fileName);
                } else {
                    url = getS3Url(tviconNode);
                }
            } catch (PathNotFoundException e) {
                e.printStackTrace();
            } catch (RepositoryException e) {
                e.printStackTrace();
            } catch (NotActiveException e) {
                e.printStackTrace();
            }

            return url;
        } else {
            return "";
        }
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getSubtitleUrl(Node node, String lang) {

        String fileName = null;
        Node subtitle_node;
        Node transformation_node;

        // Checks if subtitle exists
        try {
            // IT'S A CONTENT OR REVISION
            if (node.hasProperty(RESOURCETYPE)
                    && (CONTENT_RESOURCETYPE.equals(node.getProperty(RESOURCETYPE).getString())
                            || REVISION_RESOURCETYPE.equals(node.getProperty(RESOURCETYPE).getString()))
                    && node.hasNode(SOURCES_FOLDER + "/fuente_default")) { // it's a
                // content or
                // a revision

                Node fuente_default = node.getNode(SOURCES_FOLDER + "/fuente_default");

                if (lang != null) { // specified language
                    String subFolder = SOURCES_FOLDER + "/" + FUENTE_DEFAULT + "/transcriptions/" + lang
                            + "/subtitle";
                    if (node.hasNode(subFolder)) {
                        NodeIterator it = node.getNodes(subFolder);
                        if (it.hasNext()) { // return the first one
                            subtitle_node = it.nextNode();
                            if (log.isInfoEnabled())
                                log.info("getSubtitleUrl, subtitle_node: " + subtitle_node.getPath());
                        } else {
                            if (log.isInfoEnabled())
                                log.info("getSubtitleUrl, there is no subtitle in " + subFolder);
                            return "";
                        }
                    } else {
                        if (log.isInfoEnabled())
                            log.info("getSubtitleUrl, there is no folder " + subFolder);
                        return "";
                    }
                } else { // return subtitle_default
                    if (fuente_default.hasProperty(PROP_DEFAULT_SUBTITLE)) {
                        String relPath = fuente_default.getProperty(PROP_DEFAULT_SUBTITLE).getString();
                        subtitle_node = fuente_default.getNode(relPath.substring(1));
                        if (log.isInfoEnabled())
                            log.info("getSubtitleUrl, subtitle_node: " + subtitle_node.getPath());
                    } else {
                        if (log.isInfoEnabled())
                            log.info("getSubtitleUrl, there is no prop " + PROP_DEFAULT_SUBTITLE);
                        return "";
                    }

                }
                transformation_node = subtitle_node.getNode("transformations/subtitle_preview");
                if (log.isInfoEnabled())
                    log.info("getSubtitleUrl, transformation_node: " + transformation_node.getPath());
                fileName = content_creation.getFilenameFromNode(transformation_node, "");

                if (log.isInfoEnabled())
                    log.info("getSubtitleUrl, filename: " + fileName);

                return s3backend.getUrl(fileName);
            }

            // IT'S A SOURCE
            else if (node.hasProperty(RESOURCETYPE)
                    && (SOURCE_RESOURCETYPE.equals(node.getProperty(RESOURCETYPE).getString()))) { // it's a source

                Node fuente_default = node;

                if (lang != null) { // specified language
                    String subFolder = "transcriptions/" + lang + "/subtitle";
                    if (node.hasNode(subFolder)) {
                        NodeIterator it = node.getNodes(subFolder);
                        if (it.hasNext()) { // return the first one
                            subtitle_node = it.nextNode();
                            if (log.isInfoEnabled())
                                log.info("getSubtitleUrl, subtitle_node: " + subtitle_node.getPath());
                        } else {
                            if (log.isInfoEnabled())
                                log.info("getSubtitleUrl, there is no subtitle in " + subFolder);
                            return "";
                        }
                    } else {
                        if (log.isInfoEnabled())
                            log.info("getSubtitleUrl, there is no folder " + subFolder);
                        return "";
                    }
                } else { // return subtitle_default
                    if (fuente_default.hasProperty(PROP_DEFAULT_SUBTITLE)) {
                        String relPath = fuente_default.getProperty(PROP_DEFAULT_SUBTITLE).getString();
                        subtitle_node = fuente_default.getNode(relPath.substring(1));
                        if (log.isInfoEnabled())
                            log.info("getSubtitleUrl, subtitle_node: " + subtitle_node.getPath());
                    } else {
                        if (log.isInfoEnabled())
                            log.info("getSubtitleUrl, there is no prop " + PROP_DEFAULT_SUBTITLE);
                        return "";
                    }

                }
                transformation_node = subtitle_node.getNode("transformations/subtitle_preview");
                if (log.isInfoEnabled())
                    log.info("getSubtitleUrl, transformation_node: " + transformation_node.getPath());
                fileName = content_creation.getFilenameFromNode(transformation_node, "");

                if (log.isInfoEnabled())
                    log.info("getSubtitleUrl, filename: " + fileName);

                return s3backend.getUrl(fileName);
            }

        } catch (RepositoryException e1) {
            e1.printStackTrace();
        } catch (Exception e) {
            log.error("getSubtitleUrl, Error using S3 service");
        }
        return "";

    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getAudiodescriptionUrl(Node node, String lang) {

        String fileName = null;
        Node audio_node;
        Node transformation_node;

        // Checks if audio exists
        try {
            if (node.hasProperty(RESOURCETYPE)
                    && (CONTENT_RESOURCETYPE.equals(node.getProperty(RESOURCETYPE).getString())
                            || REVISION_RESOURCETYPE.equals(node.getProperty(RESOURCETYPE).getString()))
                    && node.hasNode(SOURCES_FOLDER + "/fuente_default")) { // it's a
                // content or
                // a revision

                Node fuente_default = node.getNode(SOURCES_FOLDER + "/fuente_default");

                if (lang != null) { // specified language
                    String subFolder = SOURCES_FOLDER + "/" + FUENTE_DEFAULT + "/transcriptions/" + lang
                            + "/audiodescription";
                    if (node.hasNode(subFolder)) {
                        NodeIterator it = node.getNodes(subFolder);
                        if (it.hasNext()) { // return the first one
                            audio_node = it.nextNode();
                            if (log.isInfoEnabled())
                                log.info("getAudiodescriptionUrl, audio_node: " + audio_node.getPath());
                        } else {
                            if (log.isInfoEnabled())
                                log.info("getAudiodescriptionUrl, there is no audio in " + subFolder);
                            return "";
                        }
                    } else {
                        if (log.isInfoEnabled())
                            log.info("getAudiodescriptionUrl, there is no folder " + subFolder);
                        return "";
                    }
                } else { // return audio_default
                    if (fuente_default.hasProperty(PROP_DEFAULT_AUDIODESCRIPTION)) {
                        String relPath = fuente_default.getProperty(PROP_DEFAULT_AUDIODESCRIPTION).getString();
                        audio_node = fuente_default.getNode(relPath.substring(1));
                        if (log.isInfoEnabled())
                            log.info("getAudiodescriptionUrl, audio_node: " + audio_node.getPath());
                    } else {
                        if (log.isInfoEnabled())
                            log.info("getAudiodescriptionUrl, there is no prop " + PROP_DEFAULT_AUDIODESCRIPTION);
                        return "";
                    }

                }
                transformation_node = audio_node.getNode("transformations/audio_preview");
                if (log.isInfoEnabled())
                    log.info("getAudiodescriptionUrl, transformation_node: " + transformation_node.getPath());
                fileName = content_creation.getFilenameFromNode(transformation_node, "");

                if (log.isInfoEnabled())
                    log.info("getAudiodescriptionUrl, filename: " + fileName);

                return s3backend.getUrl(fileName);
            }

        } catch (RepositoryException e1) {
            e1.printStackTrace();
        } catch (Exception e) {
            log.error("getAudiodescriptionUrl, Error using S3 service");
        }
        return "";

    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getDownloadUrl(Node node) {

        String url = "";
        String fileName = null;

        try {

            // GET the source
            Node source = null;
            // if node is a content or revision, the source is fuente_default
            if ((node.hasProperty(RESOURCETYPE)
                    && CONTENT_RESOURCETYPE.equals(node.getProperty(RESOURCETYPE).getString()))
                    || (node.hasProperty(RESOURCETYPE)
                            && REVISION_RESOURCETYPE.equals(node.getProperty(RESOURCETYPE).getString()))) {
                source = node.getNode("sources/fuente_default");
            } else if (node.hasProperty(RESOURCETYPE)
                    && SOURCE_RESOURCETYPE.equals(node.getProperty(RESOURCETYPE).getString())) {
                source = node;
            }

            if (source != null) {

                Node trans = null;

                // check if transformation exists
                if (!source.hasNode("transformations/gad_download") || ("".equals(
                        source.getNode("transformations/gad_download").getProperty(FILE_PROP).getString()))) {

                    if (source.hasNode("transformations/gad_download")) { // delete node
                        Node nodeAux = source.getNode("transformations/gad_download");
                        Node nodeAuxParent = nodeAux.getParent();
                        nodeAux.remove();
                        nodeAuxParent.save();
                    }

                    String revisionName = source.getParent().getParent().getName();
                    String fromPath = "/content/catalogo/revisados/" + revisionName + "/sources/" + source.getName()
                            + "/transformations/gad_download";
                    String toPath = source.getPath() + "/transformations/gad_download";

                    // if exists in catalog, then copy the trans
                    if (rootNode.hasNode(fromPath.substring(1))) {
                        if (log.isInfoEnabled())
                            log.info("getDownloadUrl, copying gad_download transformation from catalog");
                        rootNode.getSession().getWorkspace().copy(fromPath, toPath);
                        trans = source.getNode("transformations/gad_download");
                    }
                } else {
                    trans = source.getNode("transformations/gad_download");
                }

                if (trans != null) {
                    fileName = content_creation.getFilenameFromNode(trans, "");
                    url = getExternalUrl(source, "gad_download");
                }
            }
        } catch (RepositoryException e) {
            e.printStackTrace();
        }

        return url;

    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public String getOriginalUrl(Node node) {
        String url = "";

        try {
            if (node.hasProperty("sling:resourceType")) {
                if (node.hasProperty("file") && (!"".equals(node.getProperty("file").getValue().getString()))) {
                    String file = node.getProperty("file").getValue().getString();
                    url = this.downloader_tool.getUrl(file);
                }
            }
        } catch (ValueFormatException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (PathNotFoundException e) {
            e.printStackTrace();
        } catch (RepositoryException e) {
            e.printStackTrace();
        } catch (NotActiveException e) {
            e.printStackTrace();
        }

        return url;
    }

    /*
     * @see org.iavante.sling.gad.content.ContentTools
     */
    public Boolean is_valid_content(Node content) {

        boolean validated = true;
        try {
            ArrayList<String> sourcesInSchema = getSourcesinSchema(content);
            Iterator<String> iter = sourcesInSchema.iterator();

            while (iter.hasNext()) {
                String source_name = (String) iter.next();

                // Ignore "sources/subtitle_default"
                if (subTag.compareTo(source_name) != 0
                        && ((!content.hasNode(source_name)) || (is_empty_source(content.getNode(source_name))))) {
                    if (log.isInfoEnabled())
                        log.info("Content not validated");
                    return false;
                }
            }
        } catch (PathNotFoundException e) {
            e.printStackTrace();
        } catch (RepositoryException e) {
            e.printStackTrace();
        }
        if (log.isInfoEnabled())
            log.info("Content validated");
        return validated;
    }

    public String getXSPFUrl(String content_path) {

        String url = "";
        String encTicket = "";

        try {
            encTicket = serviceProvider.get_service_ticket("downloader");
            log.info("getXSPFUrl, encTicket: " + encTicket);
            encTicket = new String(Base64.encodeBase64(encTicket.getBytes()));
            log.info("getXSPFUrl, encTicket: " + encTicket);
        } catch (Exception e) {
            e.printStackTrace();
        }

        url = this.public_url + content_path + ".xspf.xml" + "?ticket=" + encTicket + "&ext=.xml";

        return url;
    }

    /*
     * (non-Javadoc)
     * @see
     * org.iavante.sling.gad.content.ContentTools#getPlaylistUrl(javax.jcr.Node)
     */
    public String getPlaylistUrl(String content_path) {

        String url = "";
        String encTicket = "";

        try {
            encTicket = serviceProvider.get_service_ticket("downloader");
            log.info(encTicket);
            encTicket = new String(Base64.encodeBase64(encTicket.getBytes()));
            log.info(encTicket);
        } catch (Exception e) {
            e.printStackTrace();
        }

        url = this.public_url + content_path + ".playlist.xml" + "?ticket=" + encTicket + "&ext=.xml";
        return url;

    }

    // ----------------- Internal ------------------
    /**
     * Returns the public content url.
     * 
     * @param node
     *          The current node
     * @return url
     */
    private String get_url(Node node) throws RepositoryException {

        String url = "";
        String format = "";

        String fileName = content_creation.getFilenameFromNode(node, format);

        if (fileName.equals("")) {
            return "";
        }

        try {
            url = downloader_tool.getUrl(fileName);
        } catch (NotActiveException e) {
            e.printStackTrace();
        }

        if (fileName.endsWith(".flv"))
            url = url + ".flv";

        if (log.isInfoEnabled())
            log.info("Downloader url: " + url);
        return url;
    }

    /**
     * Return a boolean that indicate if the storage of a content is external or
     * internal: external True, internal False.
     * 
     * @param node
     *          is a node
     * @return true of false, depending if the storage is external
     */
    private boolean isStoredExternal(Node node) throws RepositoryException {
        Node actualnode = node;

        while (actualnode.getName().contentEquals("colecciones") == false) {
            actualnode = actualnode.getParent();
            if (actualnode.getName().equals("/") || actualnode.getName().equals("content"))
                break;
        }
        if (actualnode.getName().contentEquals("colecciones") == true)
            if (actualnode.getProperty("extern_storage").equals("on") == true)
                return true;

        return false;
    }

    /**
     * Returns a smil with replaces values.
     * 
     * @param node
     *          to get the values for the replacement of the SMIL
     * @param schema
     *          is the original SMIL for the replacement
     * @return a modified SMIL with the marks of properties changes with the
     *         properties values of node
     */
    private String replaceWithNodeValues(Node node, String schema) {
        ArrayList<String> properties = getPropertiesKeys(schema);
        String result = schema;
        ListIterator<String> itera = properties.listIterator();
        String key = null;
        String value = null;
        while (itera.hasNext()) {
            key = itera.next();
            try {
                value = node.getProperty(key).getString();

            } catch (PathNotFoundException e) {
                value = unknown_value;
                log.error(e.toString());
            } catch (RepositoryException e) {
                log.error(e.toString());
                value = unknown_value;
            }
            result = result.replace(property_key_open + key + property_key_close, value);
        }
        return result;
    }

    /**
     * Extract property keys to replace.
     * 
     * @param orig
     *          is the SMIL with the keys we need to extract
     * @return a list of string keys defined by *property_key_open* and
     *         *property_key_close*
     */
    private ArrayList<String> getPropertiesKeys(String orig) {
        int begin = -1;
        int end = orig.length() - 1;
        String result = orig;
        ArrayList<String> properties = new ArrayList<String>();

        begin = result.indexOf(property_key_open);
        while (begin != -1) {
            end = result.indexOf(property_key_close, begin);
            if (end == -1) // is bad formed
                return properties;
            properties.add(result.substring(begin + 2, end));
            begin = orig.indexOf(property_key_open, end);
        }
        return properties;
    }

    /**
     * Replace Smil's properties with methods.
     * 
     * @param content
     *          is the node base to execute the method
     * @param schema
     *          is the schema where is defined the methods to execute and for
     *          replacement with the return value
     * @param storage
     *          "external" or "internal"
     * @return a modified SMIL with the methods keys changed for the return of
     *         methods defined in the original schema
     */
    private String replaceWithReturnOfMethods(Node content, String schema, String storage) {
        ArrayList<HashMap<String, String>> methodslist = getMethodsKeys(schema);

        String result = schema;
        String met = "";
        for (HashMap<String, String> methods : methodslist)
            for (String path : methods.keySet()) {
                met = methods.get(path);
                if (met.compareTo("get_url") == 0) {
                    try {

                        String st = "";
                        if (storage.compareTo("internal") == 0) {
                            st = get_url(content.getNode(path));
                        } else
                            st = getS3Url(content.getNode(path));
                        result = result.replace(method_key_open + path + ":" + met + method_key_close, st);
                    } catch (ValueFormatException e) {
                        log.error(e.toString());
                    } catch (PathNotFoundException e) {
                        log.error(e.toString());
                    } catch (RepositoryException e) {
                        log.error(e.toString());
                    }
                }
                if (met.compareTo("get_title") == 0) {
                    try {

                        String st = content.getNode(path).getProperty("title").getString();
                        result = result.replace(method_key_open + path + ":" + met + method_key_close, st);
                    } catch (ValueFormatException e) {
                        log.error(e.toString());
                    } catch (PathNotFoundException e) {
                        log.error(e.toString());
                        log.error(path);
                    } catch (RepositoryException e) {
                        log.error(e.toString());
                    }
                }
            }
        return result;
    }

    /**
     * Returns a map with the relative path and the method.
     * 
     * @param orig
     *          is the SMIL with the methods keys we need to extract
     * @return a hashmap with the relative path and the method.
     */
    private ArrayList<HashMap<String, String>> getMethodsKeys(String orig) {
        int begin = -1;
        int end = orig.length() - 1;
        String result = orig;
        ArrayList<HashMap<String, String>> methods = new ArrayList<HashMap<String, String>>();

        begin = result.indexOf(method_key_open);
        while (begin != -1) {
            end = result.indexOf(method_key_close, begin + 2);
            if (end == -1) // is bad formed
                return methods;
            HashMap<String, String> entry = new HashMap<String, String>();
            entry.put(result.substring(begin + 2, end).split(":")[0],
                    result.substring(begin + 2, end).split(":")[1]);
            methods.add(entry);
            begin = orig.indexOf(method_key_open, end);
        }

        return methods;
    }

    /**
     * Checks if playlist mark exists.
     * 
     * @param schema
     *          to parse
     * @return true if the schema has the playlist mark, false in other cases
     */
    private boolean hasPlaylistMark(String schema) {
        return schema.contains(method_playlist);
    }

    /**
     * Returns playlist lines.
     * 
     * @param content
     *          the node to get the sources media line of smil
     * @param storage
     *          if the storage is external or internal
     * @return an ArrayList<String> with the lines of sources in SMIL format
     */
    public List<String> getPlaylistLines(Node content, String storage) {
        List<String> lines = new ArrayList<String>();
        Map<String, String> ma = new HashMap<String, String>();
        String thumbnail = "";
        NodeIterator it = null;
        boolean needEnding = false;

        try {
            // check if multimedia_assets are needed.
            if (content.getProperty("sling:resourceType").getValue().getString()
                    .compareToIgnoreCase("gad/revision") == 0) {
                if (content.hasProperty("needEnding")
                        && content.getProperty("needEnding").getValue().getString().compareToIgnoreCase("1") == 0) {
                    needEnding = true;
                }
            }
            if (needEnding && content.getPath().contains("canales")) {
                ma = getMultimediaAssets(content);
            }

            assert content.getProperty("sling:resourceType").getValue().getString()
                    .compareToIgnoreCase("gad/content") == 0;
            it = content.getNode(SOURCES_FOLDER).getNodes();

        } catch (RepositoryException e) {
            log.error("getPlaylistLines," + e.toString());
            e.printStackTrace();
        }

        try {

            boolean hasVideo = false;
            Node nod = null;
            while (it.hasNext()) {

                nod = it.nextNode();
                if (nod.hasProperty("sling:resourceType") && nod.getProperty("sling:resourceType").getString()
                        .compareToIgnoreCase("gad/source") == 0) {
                    // storage
                    String st = "";

                    if (storage.compareTo("internal") == 0) {
                        st = get_url(nod);
                    } else {
                        st = getS3Url(nod);
                    }

                    if (nod.getProperty("type").getString().compareToIgnoreCase("image") == 0
                            || nod.getProperty("type").getString().compareToIgnoreCase("imagen") == 0) {

                        thumbnail = "\n\t\t<image title=\"" + nod.getProperty("title").getString() + "\" src=\""
                                + st + "\"  region=\"background\" dur=\"2s\" />";
                        lines.add(0, thumbnail);
                    }

                    if (nod.getProperty("type").getString().compareToIgnoreCase("text") == 0) {
                        // subtitle does nothing??
                    }

                    if (nod.getProperty("type").getString().compareToIgnoreCase("video") == 0) {

                        if (nod.hasProperty("length")) {
                            String length = nod.getProperty("length").getString();
                            if (length.length() > 8) {

                                int hours = Integer.parseInt(length.substring(0, 2));

                                int minutes = Integer.parseInt(length.substring(3, 5));

                                int seconds = Integer.parseInt(length.substring(6, 8));

                                String milliseconds = length.substring(9);

                                if (milliseconds.length() == 1) {
                                    milliseconds = milliseconds + "00";
                                }
                                if (milliseconds.length() == 2) {
                                    milliseconds = milliseconds + "0";
                                }

                                int millis = Integer.parseInt(milliseconds);
                                if (millis > 500) {
                                    seconds = seconds + 1;
                                }

                                int totalSecs = (hours * 60 * 60) + (minutes * 60) + seconds;

                                lines.add("\n\t\t<" + nod.getProperty("type").getString() + " title=\""
                                        + nod.getProperty("title").getString() + "\" src=\"" + st + "\" dur=\""
                                        + totalSecs + "s" + "\"  region=\"background\" />");
                            }
                        }
                        // Add the ending, if needed
                        if (nod.getProperty("type").getString().contains("video")) {
                            hasVideo = true;
                        }
                    }
                }
            }

            // Add the ending video
            if (needEnding && hasVideo && ((String) ma.get("ending") != null)) {
                Node endingNode = rootNode.getNode(((String) ma.get("ending")).substring(1));
                String endingSt = (storage.contains("internal")) ? get_url(endingNode) : getS3Url(endingNode);
                lines.add("\n\t\t<video title=\"" + endingNode.getProperty("title").getString() + "\" src=\""
                        + endingSt + "\"  region=\"background\" />");
            }

        } catch (ValueFormatException e) {
            log.error(e.toString());
        } catch (PathNotFoundException e) {
            if (e.toString().compareToIgnoreCase("javax.jcr.PathNotFoundException: type") == 0)
                log.info("the source has no type and doesn't be included");
            else
                log.error(e.toString());
        } catch (RepositoryException e) {
            log.error(e.toString());
        }

        return lines;
    }

    /**
     * Return a map with multimedia assets, is the revision has any.
     * 
     * @param revision
     * @return MultimediaAssets for the revision
     */
    public Map<String, String> getMultimediaAssets(Node revision) {
        Map<String, String> ma = new HashMap<String, String>();
        ma.put("ending", null);
        ma.put("tvicon", null);

        try {
            Node assets = revision.getParent().getParent().getNode("multimedia_assets");
            if (assets.hasNode("ending/transformations/preview")) {
                ma.put("ending", assets.getNode("ending").getPath());
                log.info("getMultimediaAssets, ending:" + assets.getNode("ending").getPath());
            }
            if (assets.hasNode("tvicon/transformations/image_preview")) {
                ma.put("tvicon", assets.getNode("tvicon").getPath());
                log.info("getMultimediaAssets, tvicon:" + assets.getNode("tvicon").getPath());
            }
        } catch (ItemNotFoundException e) {
            e.printStackTrace();
        } catch (AccessDeniedException e) {
            e.printStackTrace();
        } catch (RepositoryException e) {
            e.printStackTrace();
        }

        return ma;
    }

    /*
     * (non-Javadoc)
     * @see
     * org.iavante.sling.gad.content.ContentTools#number_of_votes(javax.jcr.Node)
     */
    public String number_of_votes(Node content) {
        String number_votes = "";
        Property votes = null;
        try {
            votes = content.getProperty("votes");
            number_votes = Integer.toString(votes.getValues().length);
        } catch (PathNotFoundException e) {

            e.printStackTrace();
        } catch (RepositoryException e) {

            e.printStackTrace();
        }
        return number_votes;
    }

    /*
     * (non-Javadoc)
     * @see
     * org.iavante.sling.gad.content.ContentTools#number_of_votes_points(javax
     * .jcr.Node)
     */
    public String number_of_votes_points(Node content) {
        Integer sum_votes = 0;

        Value[] votes = null;
        try {
            votes = content.getProperty("votes").getValues();
            for (int i = 0; i < votes.length; i++) {
                sum_votes += Integer.parseInt(votes[i].getString());
            }

        } catch (PathNotFoundException e) {

            e.printStackTrace();
        } catch (RepositoryException e) {

            e.printStackTrace();
        }
        return sum_votes.toString();
    }

    /*
     * (non-Javadoc)
     * @see
     * org.iavante.sling.gad.content.ContentTools#get_node_space(javax.jcr.Node)
     */
    public String get_node_space(Node node) {

        String path = "";
        String space = "";
        try {
            path = node.getPath();
            if (!path.startsWith("/" + this.base_repo_dir)) {
                path = "/" + base_repo_dir;
            }
        } catch (RepositoryException e) {

            e.printStackTrace();
        }

        if (path.startsWith("/" + this.base_repo_dir + "/canales")) {
            space = "channels";
        }

        else if (path.startsWith("/" + this.base_repo_dir + "/catalogo")) {
            space = "catalog";
        }

        else {
            space = "collections";
        }

        return space;
    }

    /*
     * (non-Javadoc)
     * @see
     * org.iavante.sling.gad.content.ContentTools#get_node_player(javax.servlet
     * .ServletRequest, javax.jcr.Node)
     */
    public String get_node_player(HttpServletRequest req, Node node) {
        String player = "";

        String lang = "es_ES";
        if (!"".equals(req.getParameter("lang"))) {
            lang = req.getParameter("lang");
        }

        boolean support_playlist = false;
        String node_path = "";
        Node sourcesNode;
        try {
            sourcesNode = node.getNode("sources");
            if ((sourcesNode.hasProperty("support_playlist"))
                    && ("1".equals(sourcesNode.getProperty("support_playlist").getValue().getString()))) {
                support_playlist = true;
            }
            node_path = node.getPath();

        } catch (PathNotFoundException e1) {

            e1.printStackTrace();
        } catch (RepositoryException e1) {

            e1.printStackTrace();
        }

        // Player variables
        HashMap<String, Object> kwargs = new HashMap<String, Object>();
        kwargs.put("video_url", this.getXSPFUrl(node_path));
        kwargs.put("subtitle_url", this.getSubtitleUrl(node, lang));
        kwargs.put("related_videos", "");

        if ("channels".equals(get_node_space(node))) {
        }

        kwargs.put("tvicon", this.getTviconUrl(node, "external"));
        kwargs.put("support_playlist", support_playlist);

        // If the node is in collections or catalog we return the s3 url
        if (("collections".equals(get_node_space(node))) || "catalog".equals(get_node_space(node))) {
            return s3backend.get_player(req, kwargs);
        }

        // If the node is in channels we have to check the channel distribution
        // server and channel distribution server configuration
        else {
            try {
                if ((node.hasProperty("sling:resourceType"))
                        && (!"".equals(node.getProperty("sling:resourceType").getValue().getString()))) {

                    String resource_type = node.getProperty("sling:resourceType").getValue().getString();
                    Node channel = null;

                    if (REVISION_RESOURCETYPE.equals(resource_type)) {
                        channel = node.getParent().getParent();
                    }

                    else if (SOURCE_RESOURCETYPE.equals(resource_type)) {
                        channel = node.getParent().getParent().getParent();
                    }

                    if ((channel.hasProperty("distribution_server"))
                            && (!"".equals(channel.getProperty("distribution_server").getValue().getString()))) {
                        String ds = channel.getProperty("distribution_server").getValue().getString();
                        if ("s3".equals(ds)) {

                            // Checks if the channel node has custom distribution server
                            // properties
                            // to instantiate the factory or not
                            Map<String, String> prop_dict = new HashMap<String, String>();

                            if (!channel.hasNode("ds_custom_props")) {
                                S3backend s3_backend = (S3backend) s3_factory.getService(prop_dict);
                                player = s3_backend.get_player(req, kwargs);
                                return player;
                            }

                            Node custom_props = channel.getNode("ds_custom_props");
                            if (custom_props.hasProperty("edited")) {
                                if (log.isInfoEnabled())
                                    log.info("Looking for custom player properties");
                                PropertyIterator props = custom_props.getProperties();

                                while (props.hasNext()) {
                                    Property prop = props.nextProperty();
                                    if (log.isInfoEnabled())
                                        log.info("Custom player properties Key: " + prop.getName() + " Value: "
                                                + prop.getValue());
                                    if (prop.getName().startsWith("player")) {
                                        prop_dict.put(prop.getName(), prop.getValue().getString());
                                    }
                                }
                                if (log.isInfoEnabled())
                                    log.info("Configuring s3 instance for custom player");
                            }

                            S3backend s3_backend = (S3backend) s3_factory.getService(prop_dict);
                            player = s3_backend.get_player(req, kwargs);
                            s3_backend = null;
                        }

                        // Static distribution server instantiation
                        else {
                            IDistributionServer myDServer = myDSProvider.get_distribution_server(ds);
                            player = myDServer.get_player(req, kwargs);
                        }
                    }
                }
            } catch (ValueFormatException e) {

                e.printStackTrace();
            } catch (IllegalStateException e) {

                e.printStackTrace();
            } catch (PathNotFoundException e) {

                e.printStackTrace();
            } catch (RepositoryException e) {

                e.printStackTrace();
            }
        }

        return player;
    }

    /**
     * Returns if the source is empty. A source is empty when its file property is
     * ""
     * 
     * @param source
     * @return
     */
    private boolean is_empty_source(Node source) {

        boolean empty = false;
        try {
            if ((!source.hasProperty(FILE_PROP))
                    || ("".equals(source.getProperty(FILE_PROP).getValue().getString()))) {
                empty = true;
            }
        } catch (ValueFormatException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (PathNotFoundException e) {
            e.printStackTrace();
        } catch (RepositoryException e) {
            e.printStackTrace();
        }

        return empty;
    }

    /**
     * Returns an Array of Strings with the sources specified in the schema.
     * 
     * @param content
     *          The content node
     * @return The sources that especified its own schema. Example:
     *         sources/fuente_default
     */
    private ArrayList<String> getSourcesinSchema(Node content) {

        String schemaFile = "";
        ArrayList<String> sourcesInSchema = new ArrayList<String>();
        try {
            Node schema = content.getNode(SOURCES_FOLDER).getNode(SCHEMA_FILE).getNode("jcr:content");
            InputStream fileStream = null;
            fileStream = schema.getProperty("jcr:data").getStream();
            schemaFile = convertStreamToString(fileStream);
        } catch (PathNotFoundException e) {
            log.error("Error getting sources from schema. Path not found:" + e);
            e.printStackTrace();
        } catch (RepositoryException e) {
            log.error("Error getting sources from schema. Repository:" + e);
            e.printStackTrace();
        }

        Pattern sourcePattern = Pattern.compile("\\[\\[.*\\]\\]");
        Matcher sourceMatcher = sourcePattern.matcher(schemaFile);

        while (sourceMatcher.find()) {
            String sourcePath = sourceMatcher.group().split(":")[0].substring(2);
            sourcesInSchema.add(sourcePath);
        }

        return sourcesInSchema;
    }

    /**
     * Convert an inputstream to a string.
     * 
     * @param is
     * @return
     */
    private String convertStreamToString(InputStream is) {
        /*
         * To convert the InputStream to String we use the BufferedReader.readLine()
         * method. We iterate until the BufferedReader return null which means
         * there's no more data to read. Each line will appended to a StringBuilder
         * and returned as String.
         */
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}