001/* 002 * Copyright 2018 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.web.frontoffice.search.metamodel.impl; 017 018import java.io.InputStream; 019import java.util.Date; 020 021import org.apache.cocoon.xml.AttributesImpl; 022import org.apache.cocoon.xml.XMLUtils; 023import org.apache.commons.lang.StringUtils; 024import org.apache.tika.Tika; 025import org.slf4j.Logger; 026import org.xml.sax.ContentHandler; 027import org.xml.sax.SAXException; 028 029import org.ametys.cms.repository.Content; 030import org.ametys.cms.transformation.xslt.ResolveURIComponent; 031import org.ametys.core.util.DateUtils; 032import org.ametys.plugins.explorer.resources.Resource; 033import org.ametys.plugins.repository.AmetysObject; 034import org.ametys.web.frontoffice.search.metamodel.ReturnableSaxer; 035import org.ametys.web.frontoffice.search.requesttime.SearchComponentArguments; 036import org.ametys.web.repository.page.Page; 037import org.ametys.web.repository.site.Site; 038 039/** 040 * {@link ReturnableSaxer} for {@link ResourceReturnable} 041 */ 042public class ResourceSaxer implements ReturnableSaxer 043{ 044 /** The associated returnable on resources */ 045 protected ResourceReturnable _resourceReturnable; 046 047 /** 048 * Constructor 049 * @param resourceReturnable The associated returnable on resources 050 */ 051 public ResourceSaxer(ResourceReturnable resourceReturnable) 052 { 053 _resourceReturnable = resourceReturnable; 054 } 055 056 @Override 057 public boolean canSax(AmetysObject hit, Logger logger, SearchComponentArguments args) 058 { 059 return hit instanceof Resource; 060 } 061 062 @Override 063 public void sax(ContentHandler contentHandler, AmetysObject hit, Logger logger, SearchComponentArguments args) throws SAXException 064 { 065 Resource resource = (Resource) hit; 066 String filename = resource.getName(); 067 XMLUtils.createElement(contentHandler, "filename", filename); 068 XMLUtils.createElement(contentHandler, "title", StringUtils.substringBeforeLast(resource.getName(), ".")); 069 070 String dcDescription = resource.getDCDescription(); 071 String excerpt = _getResourceExcerpt(resource, logger); 072 if (StringUtils.isNotBlank(dcDescription)) 073 { 074 XMLUtils.createElement(contentHandler, "excerpt", dcDescription); 075 } 076 else if (StringUtils.isNotBlank(excerpt)) 077 { 078 XMLUtils.createElement(contentHandler, "excerpt", excerpt + "..."); 079 } 080 081 XMLUtils.createElement(contentHandler, "type", "resource"); 082 083 Page page = _getResourcePage(resource); 084 Content content = _getResourceContent(resource); 085 _saxUri(contentHandler, resource, page, content); 086 XMLUtils.createElement(contentHandler, "mime-types", resource.getMimeType()); 087 _saxSize(contentHandler, resource.getLength()); 088 _saxIcon(contentHandler, filename); 089 090 Date lastModified = resource.getLastModified(); 091 if (lastModified != null) 092 { 093 XMLUtils.createElement(contentHandler, "lastModified", DateUtils.dateToString(lastModified)); 094 } 095 if (page != null) 096 { 097 Site site = page.getSite(); 098 XMLUtils.createElement(contentHandler, "siteName", site.getName()); 099 XMLUtils.createElement(contentHandler, "siteTitle", site.getTitle()); 100 XMLUtils.createElement(contentHandler, "siteUrl", site.getUrl()); 101 } 102 } 103 104 /** 105 * Get the excerpt of the resource 106 * @param resource the resource 107 * @param logger the logger to use in case of error 108 * @return the resource excerpt 109 */ 110 protected String _getResourceExcerpt(Resource resource, Logger logger) 111 { 112 try (InputStream is = resource.getInputStream()) 113 { 114 Tika tika = _resourceReturnable._tikaProvider.getTika(); 115 String value = tika.parseToString(is); 116 if (StringUtils.isNotBlank(value)) 117 { 118 int summaryEndIndex = value.lastIndexOf(' ', 200); 119 if (summaryEndIndex == -1) 120 { 121 summaryEndIndex = value.length(); 122 } 123 return value.substring(0, summaryEndIndex) + (summaryEndIndex != value.length() ? "…" : ""); 124 } 125 } 126 catch (Exception e) 127 { 128 logger.error("Unable to index resource at " + resource.getPath(), e); 129 } 130 return null; 131 } 132 133 134 /** 135 * Get the page containing the resource 136 * @param resource the resource 137 * @return the page containing the resource, null if the resource is not inside a page 138 */ 139 protected Page _getResourcePage(Resource resource) 140 { 141 if (resource != null) 142 { 143 AmetysObject parent = resource.getParent(); 144 while (parent != null) 145 { 146 if (parent instanceof Page) 147 { 148 // We have gone up to the page 149 return (Page) parent; 150 } 151 parent = parent.getParent(); 152 } 153 } 154 155 return null; 156 } 157 158 159 /** 160 * Get the content containing the resource 161 * @param resource the resource 162 * @return the content containing the resource, null if the resource is not inside a content 163 */ 164 protected Content _getResourceContent(Resource resource) 165 { 166 if (resource != null) 167 { 168 AmetysObject parent = resource.getParent(); 169 while (parent != null) 170 { 171 if (parent instanceof Content) 172 { 173 // We have gone up to the content 174 return (Content) parent; 175 } 176 parent = parent.getParent(); 177 } 178 } 179 180 return null; 181 } 182 183 /** 184 * Sax the resource URI 185 * @param contentHandler the content handler where to SAX into. 186 * @param resource the resource used to resolve the URI 187 * @param page the page used to resolve the URI 188 * @param content the content used to resolve the URI 189 * @throws SAXException if an errors occurs during the value writing 190 */ 191 protected void _saxUri(ContentHandler contentHandler, Resource resource, Page page, Content content) throws SAXException 192 { 193 String type; 194 if (page != null) 195 { 196 type = "attachment-page"; 197 } 198 else if (content != null) 199 { 200 type = "attachment-content"; 201 } 202 else 203 { 204 type = "explorer"; 205 } 206 AttributesImpl atts = new AttributesImpl(); 207 atts.addCDATAAttribute("type", type); 208 atts.addCDATAAttribute("id", resource.getId()); 209 // for legacy purpose, the uri is also resolved here, and thus ready to be used 210 String uri = ResolveURIComponent.resolve(type, resource.getId(), true); 211 XMLUtils.createElement(contentHandler, "uri", atts, uri); 212 } 213 214 /** 215 * Sax the resource size 216 * @param contentHandler the content handler where to SAX into. 217 * @param size the size to sax 218 * @throws SAXException if an errors occurs during the value writing 219 */ 220 protected void _saxSize(ContentHandler contentHandler, long size) throws SAXException 221 { 222 org.ametys.core.util.StringUtils.toReadableDataSize(size).toSAX(contentHandler, "size"); 223 } 224 225 /** 226 * Sax the resource icon 227 * @param contentHandler the content handler where to SAX into. 228 * @param filename the name of the resource 229 * @throws SAXException if an errors occurs during the value writing 230 */ 231 protected void _saxIcon(ContentHandler contentHandler, String filename) throws SAXException 232 { 233 int index = filename.lastIndexOf('.'); 234 String extension = filename.substring(index + 1); 235 236 XMLUtils.createElement(contentHandler, "icon", "plugins/explorer/icon-medium/" + extension + ".png"); 237 } 238}