Java tutorial
/* * 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(); } }