View Javadoc
1   /*
2    * Copyright (C) 2003-2013 eXo Platform SAS.
3    *
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU Affero General Public License as published by
6    * the Free Software Foundation, either version 3 of the License, or
7    * (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU Affero General Public License for more details.
13   *
14   * You should have received a copy of the GNU Affero General Public License
15   * along with this program. If not, see <http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.services.wcm.search.connector;
18  
19  import java.net.URLDecoder;
20  import java.util.Collection;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import javax.jcr.RepositoryException;
25  import javax.jcr.Session;
26  
27  import org.apache.commons.lang.StringEscapeUtils;
28  import org.apache.commons.lang.StringUtils;
29  
30  import org.exoplatform.commons.api.search.data.SearchContext;
31  import org.exoplatform.container.xml.InitParams;
32  import org.exoplatform.portal.config.DataStorage;
33  import org.exoplatform.portal.config.model.Application;
34  import org.exoplatform.portal.config.model.Container;
35  import org.exoplatform.portal.config.model.ModelObject;
36  import org.exoplatform.portal.mop.SiteKey;
37  import org.exoplatform.portal.mop.SiteType;
38  import org.exoplatform.portal.mop.navigation.*;
39  import org.exoplatform.services.cms.drives.DriveData;
40  import org.exoplatform.services.cms.impl.Utils;
41  import org.exoplatform.services.cms.templates.TemplateService;
42  import org.exoplatform.services.jcr.core.ManageableRepository;
43  import org.exoplatform.services.log.ExoLogger;
44  import org.exoplatform.services.log.Log;
45  import org.exoplatform.services.security.ConversationState;
46  import org.exoplatform.services.wcm.core.NodetypeConstant;
47  import org.exoplatform.services.wcm.search.ResultNode;
48  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
49  
50  /**
51   * Documents are nodes whose nodetype was declared as a Document Type in ECM admin.
52   */
53  public class DocumentSearchServiceConnector extends BaseContentSearchServiceConnector {
54  
55    private static final Log LOG = ExoLogger.getLogger(DocumentSearchServiceConnector.class.getName());
56    
57    public DocumentSearchServiceConnector(InitParams initParams) throws Exception {
58      super(initParams);
59    }
60  
61    /**
62     * {@inheritDoc}
63     */
64    @Override
65    protected String[] getSearchedDocTypes() {
66      List<String> docTypes = null;
67      try {
68         docTypes = WCMCoreUtils.getService(TemplateService.class).getDocumentTemplates();
69      } catch (Exception e) {
70        if (LOG.isErrorEnabled()) {
71          LOG.error(e);
72        }
73      }
74      docTypes.remove(NodetypeConstant.NT_FILE);
75      return docTypes.toArray(new String[]{});
76    }
77    
78    protected String[] getNodeTypes() {
79      return null;
80    }
81    
82    /**
83     * {@inheritDoc}
84     * @throws RepositoryException 
85     */
86    @Override
87    protected ResultNode filterNode(ResultNode node) throws RepositoryException {
88      //do not accept nt:file
89      return node.isNodeType(NodetypeConstant.NT_FILE) ? null : node;
90    }
91    
92    /**
93     * {@inheritDoc}
94     * @throws RepositoryException 
95     */
96    @Override
97    protected String getPath(ResultNode node, SearchContext context) throws Exception {
98      String url = BaseSearchServiceConnector.NONE_NAGVIGATION;
99      String handler = WCMCoreUtils.getPortalName();
100     if(StringUtils.isNotEmpty(context.getSiteName())) {
101       String siteType = StringUtils.isEmpty(context.getSiteType()) ? SiteType.PORTAL.toString() : context.getSiteType().toUpperCase();
102       SiteKey siteKey = new SiteKey(SiteType.valueOf(siteType), context.getSiteName());
103 
104       DriveData driveData = documentService.getDriveOfNode(node.getPath(), ConversationState.getCurrent().getIdentity().getUserId(), Utils.getMemberships());
105 
106       if (StringUtils.isNotBlank(siteKey.getName())) {
107         String pageName = getPageName(siteKey);
108         if (StringUtils.isNotBlank(pageName)) {
109           siteKey = SiteKey.portal(context.getSiteName() != null ? context.getSiteName() :
110                   BaseSearchServiceConnector.DEFAULT_SITENAME);
111           pageName = getPageName(siteKey);
112         }
113         try {
114           url = "/" + handler + context.handler(handler).
115                   lang("").
116                   siteName(siteKey.getName()).
117                   siteType(SiteType.PORTAL.getName()).
118                   path(pageName + "?path=" + driveData.getName() + "/" + node.getPath()).renderLink();
119         } catch (Exception e) {
120           LOG.debug("The current user does not have the needed permission to get the requested document");
121           return null;
122         }
123       }
124     }
125 
126     return URLDecoder.decode(url, "UTF-8");
127   }
128 
129   @Override
130   protected String getPreviewUrl(ResultNode node, SearchContext context) throws Exception {
131     String restContextName =  WCMCoreUtils.getRestContextName();
132 
133     Session session = node.getSession();
134     String repositoryName = ((ManageableRepository) session.getRepository()).getConfiguration().getName();
135     String workspaceName = node.getSession().getWorkspace().getName();
136 
137     StringBuffer downloadUrl = new StringBuffer();
138     downloadUrl.append('/').append(restContextName).append("/jcr/").
139             append(WCMCoreUtils.getRepository().getConfiguration().getName()).append('/').
140             append(workspaceName).append(node.getPath());
141 
142     // get document author
143     String authorUsername = null;
144     if(node.hasProperty("exo:owner")) {
145       authorUsername = node.getProperty("exo:owner").getString();
146     }
147 
148     StringBuilder url = new StringBuilder("javascript:require(['SHARED/documentPreview'], function(documentPreview) {documentPreview.init({doc:{");
149     if(node.isNodeType(NodetypeConstant.MIX_REFERENCEABLE)) {
150       url.append("id:'").append(node.getUUID()).append("',");
151     }
152 
153     String title = StringEscapeUtils.escapeHtml(getTitleResult(node)).replace("'", "\\'");
154     url.append("fileType:'").append(getFileType(node)).append("',");
155     url.append("title:'").append(title).append("',");
156     url.append("path:'").append(node.getPath())
157             .append("', repository:'").append(repositoryName)
158             .append("', workspace:'").append(workspaceName)
159             .append("', downloadUrl:'").append(downloadUrl.toString())
160             .append("', openUrl:'").append(documentService.getLinkInDocumentsApp(node.getPath()))
161             .append("'}");
162     if(authorUsername != null) {
163       url.append(",author:{username:'").append(authorUsername).append("'}");
164     }
165     //add void(0) to make firefox execute js
166     url.append("})});void(0);");
167 
168     return url.toString();
169   }
170 
171   private String getPageName(SiteKey siteKey) throws Exception {
172     NavigationService navService = WCMCoreUtils.getService(NavigationService.class);
173     NavigationContext nav = navService.loadNavigation(siteKey);
174     NodeContext<NodeContext<?>> parentNodeCtx = navService.loadNode(NodeModel.SELF_MODEL, nav, Scope.ALL, null);
175     if (parentNodeCtx.getSize() >= 1) {
176       Collection<NodeContext<?>> children = parentNodeCtx.getNodes();
177       if (siteKey.getType() == SiteType.GROUP) {
178         children = parentNodeCtx.get(0).getNodes();
179       }
180       Iterator<NodeContext<?>> it = children.iterator();
181       NodeContext<?> child = null;
182       while (it.hasNext()) {
183         child = it.next();
184         if (hasPortlet(child, BaseSearchServiceConnector.PORTLET_NAME)) {
185           return child.getName();
186         }
187       }
188     }
189     return "";
190   }
191   
192   private boolean hasPortlet(NodeContext<?> pageCt, String plName) {
193     if (plName == null) return false;
194     DataStorage ds = WCMCoreUtils.getService(DataStorage.class);
195     try {
196       for (ModelObject mo : ds.getPage(pageCt.getState().getPageRef().format()).getChildren()) {
197         if (containApp(mo, plName)) {
198           return true;
199         }
200       } //of for
201     } catch(Exception ex) {
202       return false;
203     }
204     return false;
205   }
206   
207   private boolean containApp(ModelObject mo, String plName) {
208     DataStorage ds = WCMCoreUtils.getService(DataStorage.class);
209     if (mo instanceof Application<?>) {
210       try {
211         if (ds.getId(((Application<?>)mo).getState()).contains(plName)) {
212           return true;
213         }
214       } catch (Exception e) {
215         return false;
216       }
217     } else if (mo instanceof Container) {
218       for (ModelObject m : ((Container)mo).getChildren()) {
219         if (containApp(m, plName)) {
220           return true;
221         }// of if
222       }// of for
223     } // of flse
224     return false;
225   }
226   
227 }