View Javadoc
1   /*
2    * Copyright (C) 2003-2007 eXo Platform SEA.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (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 General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.wcm.connector.fckeditor;
18  
19  import java.net.URLDecoder;
20  import java.text.DateFormat;
21  import java.text.SimpleDateFormat;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.Comparator;
27  import java.util.Date;
28  import java.util.List;
29  import java.util.Locale;
30  import java.util.MissingResourceException;
31  import java.util.ResourceBundle;
32  
33  import javax.annotation.security.RolesAllowed;
34  import javax.jcr.Node;
35  import javax.jcr.NodeIterator;
36  import javax.jcr.RepositoryException;
37  import javax.jcr.Session;
38  import javax.servlet.http.HttpServletRequest;
39  import javax.ws.rs.GET;
40  import javax.ws.rs.POST;
41  import javax.ws.rs.Path;
42  import javax.ws.rs.QueryParam;
43  import javax.ws.rs.core.CacheControl;
44  import javax.ws.rs.core.Context;
45  import javax.ws.rs.core.MediaType;
46  import javax.ws.rs.core.Response;
47  import javax.xml.parsers.DocumentBuilder;
48  import javax.xml.parsers.DocumentBuilderFactory;
49  import javax.xml.transform.dom.DOMSource;
50  
51  import org.apache.commons.lang.StringUtils;
52  import org.w3c.dom.Document;
53  import org.w3c.dom.Element;
54  import org.w3c.dom.NodeList;
55  
56  import org.exoplatform.container.xml.InitParams;
57  import org.exoplatform.ecm.connector.fckeditor.FCKUtils;
58  import org.exoplatform.ecm.utils.text.Text;
59  import org.exoplatform.services.cms.BasePath;
60  import org.exoplatform.services.cms.documents.DocumentService;
61  import org.exoplatform.services.cms.drives.DriveData;
62  import org.exoplatform.services.cms.drives.ManageDriveService;
63  import org.exoplatform.services.cms.impl.Utils;
64  import org.exoplatform.services.cms.link.LinkManager;
65  import org.exoplatform.services.cms.link.NodeFinder;
66  import org.exoplatform.services.cms.templates.TemplateService;
67  import org.exoplatform.services.jcr.RepositoryService;
68  import org.exoplatform.services.jcr.core.ManageableRepository;
69  import org.exoplatform.services.jcr.ext.common.SessionProvider;
70  import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
71  import org.exoplatform.services.log.ExoLogger;
72  import org.exoplatform.services.log.Log;
73  import org.exoplatform.services.resources.ResourceBundleService;
74  import org.exoplatform.services.rest.resource.ResourceContainer;
75  import org.exoplatform.services.security.ConversationState;
76  import org.exoplatform.services.security.Identity;
77  import org.exoplatform.services.security.IdentityRegistry;
78  import org.exoplatform.services.security.MembershipEntry;
79  import org.exoplatform.services.wcm.core.NodeLocation;
80  import org.exoplatform.services.wcm.core.NodetypeConstant;
81  import org.exoplatform.services.wcm.portal.PortalFolderSchemaHandler;
82  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
83  import org.exoplatform.services.wcm.webcontent.WebContentSchemaHandler;
84  import org.exoplatform.wcm.connector.BaseConnector;
85  import org.exoplatform.wcm.connector.FileUploadHandler;
86  import org.exoplatform.wcm.connector.handler.FCKFileHandler;
87  
88  /**
89   * Returns a list of drives/folders/documents in a specified location for a given user. Also, it processes the file uploading action.
90   *
91   * {{{{portalname}}}}: The name of portal.
92   * {{{{restcontextname}}}}: The context name of REST web application which is deployed to the "{{{{portalname}}}}" portal.
93   *
94   * @LevelAPI Provisional
95   * @anchor DriverConnector
96   */
97  @Path("/wcmDriver/")
98  public class DriverConnector extends BaseConnector implements ResourceContainer {
99  
100   /** The Constant FILE_TYPE_WEBCONTENT. */
101   public static final String FILE_TYPE_WEBCONTENT                        = "Web Contents";
102 
103   /** The Constant FILE_TYPE_DMSDOC. */
104   public static final String FILE_TYPE_DMSDOC                        = "DMS Documents";
105 
106   /** The Constant FILE_TYPE_MEDIAS. */
107   public static final String FILE_TYPE_MEDIAS                       = "Medias";
108 
109   /** The Constant FILE_TYPE_MEDIAS. */
110   public static final String FILE_TYPE_ALL                       = "All";
111 
112   /** The Constant FILE_TYPE_IMAGE. */
113   public static final String FILE_TYPE_IMAGE                       = "Image";
114 
115   /** The Constant FILE_TYPE_SIMPLE_IMAGE for JPG/JPEG, PNG and GIF. */
116   public static final String FILE_TYPE_SIMPLE_IMAGE                       = "SimpleImage";
117 
118   /** The Constant MEDIA_MIMETYPE. */
119   public static final String[] MEDIA_MIMETYPE = new String[]{"application", "image", "audio", "video"};
120 
121   /** The Constant MEDIA_MIMETYPE. */
122   public static final String[] IMAGE_MIMETYPE = new String[]{"image"};
123 
124   /** The Constant MEDIA_MIMETYPE. */
125   public static final String[] SIMPLE_IMAGE_MIMETYPE = new String[]{"image/png", "image/jpg", "image/jpeg", "image/gif"};
126 
127   public static final String TYPE_FOLDER = "folder";
128 
129   public static final String TYPE_EDITOR = "editor";
130 
131   public static final String TYPE_CONTENT = "multi";
132 
133   /** The log. */
134   private static final Log LOG = ExoLogger.getLogger(DriverConnector.class.getName());
135 
136   /** The limit. */
137   private int limit;
138 
139   /** The file number limit on client side. */
140   private int limitCountClient_ = 3;
141 
142   /** The file number limit on server side. */
143   private int limitCountServer_ = 30;
144 
145   private List<String> browsableContent =new ArrayList<String>();
146 
147 
148   private ResourceBundleService resourceBundleService=null;
149   private NodeFinder nodeFinder_ = null;
150   private LinkManager linkManager_ = null;
151 
152   private String resourceBundleNames[];
153 
154   private DocumentService documentService;
155 
156   /**
157    * Instantiates a new driver connector.
158    *
159    * @param params The init parameters.
160    */
161   public DriverConnector(InitParams params, DocumentService documentService) {
162     this.documentService = documentService;
163     limit = Integer.parseInt(params.getValueParam("upload.limit.size").getValue());
164     if (params.getValueParam("upload.limit.count.client") != null) {
165       limitCountClient_ = Integer.parseInt(params.getValueParam("upload.limit.count.client").getValue());
166     }
167     if (params.getValueParam("upload.limit.count.server") != null) {
168       limitCountServer_ = Integer.parseInt(params.getValueParam("upload.limit.count.server").getValue());
169     }
170     if (params.getValueParam("exo.ecms.content.browsable") != null) {
171       browsableContent = Arrays.asList((params.getValueParam("exo.ecms.content.browsable").getValue()).split("\\s*,\\s*"));
172     }
173   }
174 
175   /**
176    * Gets the maximum size of the uploaded file.
177    * @return The file size limit.
178    */
179   public int getLimitSize() { return limit; }
180 
181   /**
182    * Gets the maximum number of files uploaded from the client side.
183    * @return The maximum number of files uploaded on the client side.
184    */
185   public int getMaxUploadCount() { return limitCountClient_; }
186 
187   /**
188    * Returns the driveName according to the nodePath param which is composed by the driveHomePath and the path of the node
189    * @param nodePath the path of the webContent
190    * @return the driveName
191    * @throws Exception
192    */
193   @GET
194   @Path("/getDriveOfNode/")
195   @RolesAllowed("users")
196   public Response getDriveOfNode(@QueryParam("nodePath") String nodePath) throws Exception {
197     DriveData drive = documentService.getDriveOfNode(nodePath);
198     String driveName = null;
199     if (drive != null) {
200       driveName = drive.getName();
201     }
202     DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
203     return Response.ok(driveName, MediaType.TEXT_PLAIN).header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date())).build();
204   }
205 
206   /**
207    * Returns a list of drives for the current user.
208    *
209    * @param lang The language of the drive name.
210    * @return The drives.
211    * @throws Exception The exception
212    *
213    * @anchor DriverConnector.getDrivers
214    */
215   @GET
216   @Path("/getDrivers/")
217   @RolesAllowed("users")
218   public Response getDrivers(@QueryParam("lang") String lang) throws Exception {
219     ConversationState conversationState = ConversationState.getCurrent();
220     String userId = conversationState.getIdentity().getUserId();
221     List<DriveData> listDriver = getDriversByUserId(userId);
222     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
223     DocumentBuilder builder = factory.newDocumentBuilder();
224     Document document = builder.newDocument();
225 
226     Element rootElement = document.createElement("Connector");
227     document.appendChild(rootElement);
228 
229     rootElement.setAttribute("isUpload", "false");
230     rootElement.appendChild(appendDrivers(document, generalDrivers(listDriver), "General Drives", lang));
231     rootElement.appendChild(appendDrivers(document, groupDrivers(listDriver), "Group Drives", lang));
232     rootElement.appendChild(appendDrivers(document, personalDrivers(listDriver, userId), "Personal Drives", lang));
233 
234     CacheControl cacheControl = new CacheControl();
235     cacheControl.setNoCache(true);
236     cacheControl.setNoStore(true);
237 
238     DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
239     return Response.ok(new DOMSource(document), MediaType.TEXT_XML)
240                    .cacheControl(cacheControl)
241                    .header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date()))
242                    .build();
243   }
244 
245   /**
246    * Returns all folders and files in a given location.
247    *
248    * @param driverName The drive name.
249    * @param currentFolder The current folder.
250    * @param currentPortal The current portal.
251    * @param repositoryName The repository name.
252    * @param workspaceName The workspace name.
253    * @param filterBy The type of filter.
254    * @return The folders and files.
255    * @throws Exception The exception
256    *
257    * @anchor DriverConnector.getFoldersAndFiles
258    */
259   @GET
260   @Path("/getFoldersAndFiles/")
261   @RolesAllowed("users")
262   public Response getFoldersAndFiles(
263       @QueryParam("driverName") String driverName,
264       @QueryParam("currentFolder") String currentFolder,
265       @QueryParam("currentPortal") String currentPortal,
266       @QueryParam("repositoryName") String repositoryName,
267       @QueryParam("workspaceName") String workspaceName,
268       @QueryParam("filterBy") String filterBy,
269       @QueryParam("type") String type)
270       throws Exception {
271     try {
272       RepositoryService repositoryService = WCMCoreUtils.getService(RepositoryService.class);
273       ManageDriveService manageDriveService = WCMCoreUtils.getService(ManageDriveService.class);
274 
275       SessionProvider sessionProvider = WCMCoreUtils.getUserSessionProvider();
276       ManageableRepository manageableRepository = repositoryService.getCurrentRepository();
277       DriveData drive = manageDriveService.getDriveByName(Text.escapeIllegalJcrChars(driverName));
278       workspaceName = drive.getWorkspace();
279       Session session = sessionProvider.getSession(workspaceName, manageableRepository);
280       Node node = getParentFolderNode(workspaceName, Text.escapeIllegalJcrChars(driverName), Text.escapeIllegalJcrChars(currentFolder));
281       return buildXMLResponseForChildren(node,
282                                          null,
283                                          filterBy,
284                                          session,
285                                          currentPortal,
286                                          currentFolder,
287                                          Text.escapeIllegalJcrChars(driverName), type);
288 
289     } catch (Exception e) {
290       if (LOG.isErrorEnabled()) {
291         LOG.error("Error when perform getFoldersAndFiles: ", e);
292       }
293     }
294 
295     DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
296     return Response.ok().header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date())).build();
297   }
298 
299 
300   /**
301    * Checks if the drive can upload a new file.
302    *
303    * @return Response containing the status indicating if upload is available.
304    * @throws Exception
305    * @anchor DriverConnector.checkUploadAvailable
306    */
307   @GET
308   @Path("/uploadFile/checkUploadAvailable/")
309   @RolesAllowed("users")
310   public Response checkUploadAvailable() throws Exception {
311     CacheControl cacheControl = new CacheControl();
312     cacheControl.setNoCache(true);
313     DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
314     String msg = fileUploadHandler.getUploadingFileCount() < limitCountServer_ ? "uploadAvailable" : "uploadNotAvailable";
315     return Response.ok(createDOMResponse(msg), MediaType.TEXT_XML)
316                     .cacheControl(cacheControl)
317                     .header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date()))
318                     .build();
319   }
320 
321   /**
322    * Uploads a file.
323    *
324    * @param uploadId The Id of the uploaded file.
325    * @return The response.
326    * @throws Exception The exception
327    *
328    * @anchor DriverConnector.uploadFile
329    */
330   @POST
331   @Path("/uploadFile/upload/")
332   @RolesAllowed("users")
333   public Response uploadFile(@Context HttpServletRequest servletRequest,
334       @QueryParam("uploadId") String uploadId) throws Exception {
335     //check if number of file uploading is greater than the limit
336 //    if (fileUploadHandler.getUploadingFileCount() >= limitCountServer_) {
337 //      CacheControl cacheControl = new CacheControl();
338 //      cacheControl.setNoCache(true);
339 //      DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
340 //      return Response.ok(createDOMResponse("uploadNotAvailable"), MediaType.TEXT_XML)
341 //                      .cacheControl(cacheControl)
342 //                      .header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date()))
343 //                      .build();
344 //    }
345     return fileUploadHandler.upload(servletRequest, uploadId, limit);
346   }
347 
348   /**
349    * Check the status of uploading a file, such as aborting, deleting or progressing the file.
350    *
351    * @param repositoryName The repository name.
352    * @param workspaceName The workspace name.
353    * @param driverName The drive name.
354    * @param currentFolder The current folder.
355    * @param currentPortal The portal name.
356    * @param language The language file.
357    * @param fileName The file name.
358    * @return The response
359    * @throws Exception The exception
360    *
361    * @anchor DriverConnector.checkExistence
362    */
363   @GET
364   @Path("/uploadFile/checkExistence/")
365   @RolesAllowed("users")
366   public Response checkExistence(
367       @QueryParam("repositoryName") String repositoryName,
368       @QueryParam("workspaceName") String workspaceName,
369       @QueryParam("driverName") String driverName,
370       @QueryParam("currentFolder") String currentFolder,
371       @QueryParam("currentPortal") String currentPortal,
372       @QueryParam("language") String language,
373       @QueryParam("fileName") String fileName) throws Exception {
374     try {
375       // Check file existence
376       Node currentFolderNode = getParentFolderNode(workspaceName,
377                                                    Text.escapeIllegalJcrChars(driverName),
378                                                    Text.escapeIllegalJcrChars(currentFolder));
379 
380       if(StringUtils.isNotEmpty(fileName)) fileName = URLDecoder.decode(fileName, "UTF-8");
381       return fileUploadHandler.checkExistence(currentFolderNode, fileName);
382     } catch (Exception e) {
383       if (LOG.isErrorEnabled()) {
384         LOG.error("Error when perform processUpload: ", e);
385       }
386     }
387 
388     DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
389     return Response.ok().header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date())).build();
390   }
391 
392   /**
393    * Clean file name
394    *
395    * @param fileName original file name
396    * @return the response
397    */
398 
399 
400   @GET
401   @Path("/uploadFile/cleanName")
402   @RolesAllowed("users")
403   public Response cleanName (@QueryParam("fileName") String fileName) throws Exception{
404     return fileUploadHandler.cleanName(fileName);
405   }
406 
407   /**
408    * Controls the process of uploading a file, such as aborting, deleting or progressing the file.
409    *
410    * @param repositoryName The repository name.
411    * @param workspaceName The workspace name.
412    * @param driverName The drive name.
413    * @param currentFolder The current folder.
414    * @param currentPortal The current portal.
415    * @param userId The user identity.
416    * @param jcrPath The path of the file.
417    * @param action The action.
418    * @param language The language.
419    * @param fileName The file name.
420    * @param uploadId The Id of upload.
421    * @param existenceAction Checks if an action exists or not.
422    * @return The response.
423    * @throws Exception The exception
424    *
425    * @anchor DriverConnector.processUpload
426    */
427   @GET
428   @Path("/uploadFile/control/")
429   @RolesAllowed("users")
430   public Response processUpload(
431       @QueryParam("repositoryName") String repositoryName,
432       @QueryParam("workspaceName") String workspaceName,
433       @QueryParam("driverName") String driverName,
434       @QueryParam("currentFolder") String currentFolder,
435       @QueryParam("currentPortal") String currentPortal,
436       @QueryParam("userId") String userId,
437       @QueryParam("jcrPath") String jcrPath,
438       @QueryParam("action") String action,
439       @QueryParam("language") String language,
440       @QueryParam("fileName") String fileName,
441       @QueryParam("uploadId") String uploadId,
442       @QueryParam("existenceAction") String existenceAction,
443       @QueryParam("srcAction") String srcAction) throws Exception {
444     try {
445       // Check upload status
446       if(StringUtils.isNotEmpty(fileName)) fileName = URLDecoder.decode(fileName, "UTF-8");
447       Response msgResponse = fileUploadHandler.checkStatus(uploadId, language);
448       if (msgResponse != null) return msgResponse;
449 
450       if ((repositoryName != null) && (workspaceName != null) && (driverName != null)
451           && (currentFolder != null)) {
452         ManageDriveService manageDriveService = WCMCoreUtils.getService(ManageDriveService.class);
453         workspaceName = workspaceName != null ? workspaceName :
454                                                 manageDriveService.getDriveByName(Text.escapeIllegalJcrChars(driverName))
455                                                                   .getWorkspace();
456 
457         Node currentFolderNode = getParentFolderNode(workspaceName,
458                                                      Text.escapeIllegalJcrChars(driverName),
459                                                      Text.escapeIllegalJcrChars(currentFolder));
460         fileName = Text.escapeIllegalJcrChars(fileName);
461         return createProcessUploadResponse(workspaceName,
462                                            currentFolderNode,
463                                            currentPortal,
464                                            userId,
465                                            Text.escapeIllegalJcrChars(jcrPath),
466                                            action,
467                                            language,
468                                            fileName,
469                                            uploadId,
470                                            existenceAction);
471       }
472     } catch (Exception e) {
473       if (LOG.isErrorEnabled()) {
474         LOG.error("Error when perform processUpload: ", e);
475       }
476     }
477 
478     DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
479     return Response.ok().header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date())).build();
480   }
481 
482   /**
483    * Gets the drives by user Id.
484    *
485    * @param userId the user Id
486    *
487    * @return the drives by user Id
488    *
489    * @throws Exception the exception
490    */
491   private List<DriveData> getDriversByUserId(String userId) throws Exception {
492     ManageDriveService driveService = WCMCoreUtils.getService(ManageDriveService.class);
493     List<String> userRoles = getMemberships(userId);
494     return driveService.getDriveByUserRoles(userId, userRoles);
495   }
496 
497   /**
498    * Appends drives.
499    *
500    * @param document The document.
501    * @param driversList The drivers list.
502    * @param groupName The group name.
503    *
504    * @return The element.
505    */
506   private Element appendDrivers(Document document,
507                                 List<DriveData> driversList,
508                                 String groupName,
509                                 String lang) throws Exception {
510     Element folders = document.createElement("Folders");
511     folders.setAttribute("name", resolveDriveLabel(groupName, lang));
512     folders.setAttribute("isUpload", "false");
513     for (DriveData driver : driversList) {
514       String repository = WCMCoreUtils.getRepository().getConfiguration().getName();
515       String workspace  = driver.getWorkspace();
516       String path = driver.getHomePath();
517       String name = driver.getName();
518       Element folder = document.createElement("Folder");
519       NodeLocation nodeLocation = new NodeLocation(repository, workspace, path);
520       Node driveNode = NodeLocation.getNodeByLocation(nodeLocation);
521       if(driveNode == null) continue;
522       folder.setAttribute("name", name);
523       folder.setAttribute("label", resolveDriveLabel(name, lang));
524       folder.setAttribute("url", FCKUtils.createWebdavURL(driveNode));
525       folder.setAttribute("folderType", "exo:drive");
526       folder.setAttribute("path", path);
527       folder.setAttribute("repository", repository);
528       folder.setAttribute("workspace", workspace);
529       folder.setAttribute("isUpload", "true");
530       folder.setAttribute("hasFolderChild", String.valueOf(this.hasFolderChild(driveNode)));
531       folder.setAttribute("nodeTypeCssClass", Utils.getNodeTypeIcon(driveNode, "uiIcon16x16"));
532 
533       folders.appendChild(folder);
534     }
535     return folders;
536   }
537 
538   private String resolveDriveLabel(String name, String lang) {
539     if (resourceBundleService == null) {
540       resourceBundleService = WCMCoreUtils.getService(ResourceBundleService.class);
541       resourceBundleNames = resourceBundleService.getSharedResourceBundleNames();
542     }
543     if (StringUtils.isBlank(lang)) {
544       lang = Locale.ENGLISH.getLanguage();
545     }
546     Locale locale = new Locale(lang);
547     ResourceBundle sharedResourceBundle = resourceBundleService.getResourceBundle(resourceBundleNames, locale);
548     try {
549       sharedResourceBundle = resourceBundleService.getResourceBundle(resourceBundleNames, locale);
550       String key = "ContentSelector.title." + name.replaceAll(" ", "");
551       if(sharedResourceBundle.containsKey(key)) {
552         return sharedResourceBundle.getString(key);
553       } else {
554         return getDriveTitle(name);
555       }
556     } catch (MissingResourceException e) {
557       if (LOG.isDebugEnabled()) {
558         LOG.debug(e.getMessage());
559       }
560     }
561     return name;
562   }
563 
564   /**
565    * Personal drivers.
566    *
567    * @param driveList the drive list
568    *
569    * @return the list< drive data>
570    * @throws Exception
571    */
572   private List<DriveData> personalDrivers(List<DriveData> driveList, String userId) throws Exception {
573     List<DriveData> personalDrivers = new ArrayList<DriveData>();
574     NodeHierarchyCreator nodeHierarchyCreator = WCMCoreUtils.getService(NodeHierarchyCreator.class);
575     SessionProvider sessionProvider = WCMCoreUtils.getSystemSessionProvider();
576     Node userNode = nodeHierarchyCreator.getUserNode(sessionProvider, userId);
577     for(DriveData drive : driveList) {
578       String driveHomePath = Utils.getPersonalDrivePath(drive.getHomePath(), userId);
579       if(driveHomePath.startsWith(userNode.getPath())) {
580         drive.setHomePath(driveHomePath);
581         personalDrivers.add(drive);
582       }
583     }
584     Collections.sort(personalDrivers);
585     return personalDrivers;
586   }
587 
588   /**
589    * Group drivers.
590    *
591    * @param driverList the driver list
592    * @return the list< drive data>
593    * @throws Exception the exception
594    */
595   private List<DriveData> groupDrivers(List<DriveData> driverList) throws Exception {
596     ManageDriveService driveService = WCMCoreUtils.getService(ManageDriveService.class);
597     String currentUserId = ConversationState.getCurrent().getIdentity().getUserId();
598     List<String> userRoles = this.getMemberships(currentUserId);
599     return driveService.getGroupDrives(currentUserId, userRoles);
600   }
601 
602   /**
603    * General drivers.
604    *
605    * @param driverList the driver list
606    *
607    * @return the list< drive data>
608    *
609    * @throws Exception the exception
610    */
611   private List<DriveData> generalDrivers(List<DriveData> driverList) throws Exception {
612     List<DriveData> generalDrivers = new ArrayList<DriveData>();
613     NodeHierarchyCreator nodeHierarchyCreator = WCMCoreUtils.getService(NodeHierarchyCreator.class);
614     String userPath = nodeHierarchyCreator.getJcrPath(BasePath.CMS_USERS_PATH);
615     String groupPath = nodeHierarchyCreator.getJcrPath(BasePath.CMS_GROUPS_PATH);
616     for(DriveData drive : driverList) {
617       if((!drive.getHomePath().startsWith(userPath) && !drive.getHomePath().startsWith(groupPath))
618           || drive.getHomePath().equals(userPath)) {
619         generalDrivers.add(drive);
620       }
621     }
622     return generalDrivers;
623   }
624 
625   /**
626    * Gets the memberships.
627    *
628    * @param userId the user id
629    *
630    * @return the memberships
631    *
632    * @throws Exception the exception
633    */
634   private List<String> getMemberships(String userId) throws Exception {
635     List<String> userMemberships = new ArrayList<String> ();
636     userMemberships.add(userId);
637     // here we must retrieve memberships of the user using the
638     // IdentityRegistry Service instead of Organization Service to
639     // allow JAAS based authorization
640     Collection<MembershipEntry> memberships = getUserMembershipsFromIdentityRegistry(userId);
641     if (memberships != null) {
642       for (MembershipEntry membership : memberships) {
643         String role = membership.getMembershipType() + ":" + membership.getGroup();
644         userMemberships.add(role);
645       }
646     }
647 
648     return userMemberships;
649   }
650 
651   /**
652    * this method retrieves memberships of the user having the given id using the
653    * IdentityRegistry service instead of the Organization service to allow JAAS
654    * based authorization
655    *
656    * @param authenticatedUser the authenticated user id
657    * @return a collection of MembershipEntry
658    */
659   private static Collection<MembershipEntry> getUserMembershipsFromIdentityRegistry(String authenticatedUser) {
660     IdentityRegistry identityRegistry = WCMCoreUtils.getService(IdentityRegistry.class);
661     Identity currentUserIdentity = identityRegistry.getIdentity(authenticatedUser);
662     return currentUserIdentity.getMemberships();
663   }
664 
665   private Response buildXMLResponseForChildren(Node node,
666                                                String command,
667                                                String filterBy,
668                                                Session session,
669                                                String currentPortal,
670                                                String currentParentFolder,
671                                                String nodeDriveName,
672                                                String type) throws Exception {
673       TemplateService templateService = WCMCoreUtils.getService(TemplateService.class);
674       Element rootElement = FCKUtils.createRootElement(command, node, folderHandler.getFolderType(node));
675       NodeList nodeList = rootElement.getElementsByTagName("CurrentFolder");
676       Element currentFolder = (Element) nodeList.item(0);
677       currentFolder.setAttribute("isUpload", "true");
678       Document document = rootElement.getOwnerDocument();
679       Element folders = document.createElement("Folders");
680       folders.setAttribute("isUpload", "true");
681       Element files = document.createElement("Files");
682       files.setAttribute("isUpload", "true");
683       Node sourceNode = null;
684       Node checkNode = null;
685       Node targetNode = null;
686       if (node.isNodeType(NodetypeConstant.EXO_SYMLINK)) {
687         targetNode = linkManager.getTarget(node);
688       } else {
689         targetNode = node;
690       }
691       List<Node> childList = new ArrayList<Node>();
692       for (NodeIterator iterator = targetNode.getNodes(); iterator.hasNext();) {
693         childList.add(iterator.nextNode());
694       }
695       Collections.sort(childList,new NodeTitleComparator());
696       for (Node child:childList) {
697         String fileType = null;
698         if (child.isNodeType(FCKUtils.EXO_HIDDENABLE))
699           continue;
700         if(TYPE_FOLDER.equals(type) && templateService.isManagedNodeType(child.getPrimaryNodeType().getName()))
701           continue;
702 
703         if(child.isNodeType("exo:symlink") && child.hasProperty("exo:uuid")) {
704           sourceNode = linkManager.getTarget(child);
705         } else {
706           sourceNode = child;
707         }
708 
709         checkNode = sourceNode != null ? sourceNode : child;
710 
711         String folderPath = child.getPath();
712         folderPath = folderPath.substring(folderPath.lastIndexOf("/") + 1, folderPath.length());
713         String childRelativePath = StringUtils.isEmpty(currentParentFolder) ? folderPath : currentParentFolder.concat("/")
714                                                                                     .concat(folderPath);
715 
716         if (isFolder(checkNode, type)) {
717           // Get node name from node path to fix same name problem (ECMS-3586)
718           String nodePath = child.getPath();
719           Element folder = createFolderElement(document, checkNode, checkNode.getPrimaryNodeType().getName(),
720                         nodePath.substring(nodePath.lastIndexOf("/") + 1, nodePath.length()),  childRelativePath, nodeDriveName, type);
721           folders.appendChild(folder);
722         }
723   
724         if (FILE_TYPE_ALL.equals(filterBy)
725             && (checkNode.isNodeType(NodetypeConstant.EXO_WEBCONTENT) || !isFolder(checkNode, type))) {
726           fileType = FILE_TYPE_ALL;
727         }
728 
729         if (FILE_TYPE_WEBCONTENT.equals(filterBy)) {
730           if(checkNode.isNodeType(NodetypeConstant.EXO_WEBCONTENT)) {
731             fileType = FILE_TYPE_WEBCONTENT;
732           }
733         }
734 
735         if (FILE_TYPE_MEDIAS.equals(filterBy) && isMediaType(checkNode)){
736           fileType = FILE_TYPE_MEDIAS;
737         }
738 
739         if (FILE_TYPE_DMSDOC.equals(filterBy) && isDMSDocument(checkNode)) {
740           fileType = FILE_TYPE_DMSDOC;
741         }
742 
743         if (FILE_TYPE_IMAGE.equals(filterBy) && isImageType(checkNode)) {
744           fileType = FILE_TYPE_IMAGE;
745         }
746 
747         if (FILE_TYPE_SIMPLE_IMAGE.equals(filterBy) && isSimpleImageType(checkNode)) {
748           fileType = FILE_TYPE_SIMPLE_IMAGE;
749         }
750 
751         if (fileType != null) {
752           Element file = FCKFileHandler.createFileElement(document, fileType, checkNode, child, currentPortal, childRelativePath, linkManager);
753           files.appendChild(file);
754         }
755       }
756 
757       rootElement.appendChild(folders);
758       rootElement.appendChild(files);
759       return getResponse(document);
760     }
761   /**
762    * Checks if is folder and is not web content.
763    *
764    * @param checkNode the check node
765    *
766    * @return true, if is folder and is not web content
767    *
768    * @throws RepositoryException the repository exception
769    */
770   private boolean isFolder(Node checkNode, String type) throws RepositoryException {
771     try {
772       if (isDocument(checkNode, type)) return false;
773     } catch (Exception e) {
774       if (LOG.isWarnEnabled()) {
775         LOG.warn(e.getMessage());
776       }
777     }
778     return
779         checkNode.isNodeType(NodetypeConstant.NT_UNSTRUCTURED)
780         || checkNode.isNodeType(NodetypeConstant.NT_FOLDER)
781         || checkNode.isNodeType(NodetypeConstant.EXO_TAXONOMY);
782   }
783 
784   /**
785    * Check if specific node has child which is type of nt:folder or nt:unstructured.
786    *
787    * @param checkNode The node to be checked
788    * @return True if the folder has some child.
789    * @throws Exception
790    */
791   private boolean hasFolderChild(Node checkNode) throws Exception {
792     return (Utils.hasChild(checkNode, NodetypeConstant.NT_UNSTRUCTURED)
793               || Utils.hasChild(checkNode, NodetypeConstant.NT_FOLDER));
794   }
795 
796   /**
797    * Checks if is dMS document.(not including free layout webcontent and media and article)
798    *
799    * @param node the node
800    *
801    * @return true, if is dMS document
802    *
803    * @throws Exception the exception
804    */
805   private boolean isDMSDocument(Node node) throws Exception {
806     TemplateService templateService = WCMCoreUtils.getService(TemplateService.class);
807     List<String> dmsDocumentListTmp = templateService.getDocumentTemplates();
808     List<String> dmsDocumentList = new ArrayList<String>();
809     dmsDocumentList.addAll(dmsDocumentListTmp);
810     dmsDocumentList.remove(NodetypeConstant.EXO_WEBCONTENT);
811     for (String documentType : dmsDocumentList) {
812       if (node.getPrimaryNodeType().isNodeType(documentType)
813           && !isMediaType(node)
814           && !node.isNodeType(NodetypeConstant.EXO_WEBCONTENT)) {
815         return true;
816       }
817     }
818     return false;
819   }
820 
821   /**
822    * Checks if specific node is document
823    *
824    * @param node specific Node
825    * @return true: is document, false: not document
826    * @throws RepositoryException
827    */
828   private boolean isDocument(Node node, String type) throws RepositoryException {
829     TemplateService templateService = WCMCoreUtils.getService(TemplateService.class);
830     List<String> documentTypeList = templateService.getDocumentTemplates();
831     if (TYPE_EDITOR.equals(type) && browsableContent != null) {
832       for (String browsableDocument : browsableContent) {
833         documentTypeList.remove(browsableDocument);
834       }
835     }
836     for (String documentType : documentTypeList) {
837       if (node.getPrimaryNodeType().isNodeType(documentType)) {
838         return true;
839       }
840     }
841     return false;
842   }
843 
844   /**
845    * Checks if is media type.
846    *
847    * @param node the node
848    *
849    * @return true, if is media type
850    */
851   private boolean isMediaType(Node node){
852     String mimeType = "";
853 
854     try {
855       mimeType = node.getNode("jcr:content").getProperty("jcr:mimeType").getString();
856     } catch (Exception e) {
857       return false;
858     }
859 
860     for(String type: MEDIA_MIMETYPE) {
861       if(mimeType.contains(type)){
862         return true;
863       }
864     }
865 
866     return false;
867   }
868 
869   /**
870    * Checks if is image of type JPG, JPEG, PNG or GIF.
871    *
872    * @param node the node
873    *
874    * @return true, if is simple image type
875    */
876   private boolean isSimpleImageType(Node node){
877     String mimeType = "";
878 
879     try {
880       mimeType = node.getNode("jcr:content").getProperty("jcr:mimeType").getString();
881     } catch (Exception e) {
882       return false;
883     }
884 
885     for(String type: SIMPLE_IMAGE_MIMETYPE) {
886       if(mimeType.equalsIgnoreCase(type)){
887         return true;
888       }
889     }
890 
891     return false;
892   }
893 
894   /**
895    * Checks if is image type.
896    *
897    * @param node the node
898    *
899    * @return true, if is image type
900    */
901   private boolean isImageType(Node node){
902     String mimeType = "";
903 
904     try {
905       mimeType = node.getNode("jcr:content").getProperty("jcr:mimeType").getString();
906     } catch (Exception e) {
907       return false;
908     }
909 
910     for(String type: IMAGE_MIMETYPE) {
911       if(mimeType.contains(type)){
912         return true;
913       }
914     }
915 
916     return false;
917   }
918 
919   /* (non-Javadoc)
920    * @see org.exoplatform.wcm.connector.BaseConnector#getContentStorageType()
921    */
922   @Override
923   protected String getContentStorageType() throws Exception {
924     return null;
925   }
926 
927   /* (non-Javadoc)
928    * @see org.exoplatform.wcm.connector.BaseConnector#getRootContentStorage(javax.jcr.Node)
929    */
930   @Override
931   protected Node getRootContentStorage(Node node) throws Exception {
932     try {
933       PortalFolderSchemaHandler folderSchemaHandler = webSchemaConfigService
934       .getWebSchemaHandlerByType(PortalFolderSchemaHandler.class);
935       return folderSchemaHandler.getImagesFolder(node);
936     } catch (Exception e) {
937       WebContentSchemaHandler webContentSchemaHandler = webSchemaConfigService
938       .getWebSchemaHandlerByType(WebContentSchemaHandler.class);
939       return webContentSchemaHandler.getImagesFolders(node);
940     }
941   }
942 
943   /**
944    *
945    * @param workspaceName The workspace name.
946    * @param currentFolderNode The current folder.
947    * @param siteName The portal name.
948    * @param userId  The user Id.
949    * @param jcrPath The path of the file.
950    * @param action The action.
951    * @param language The language.
952    * @param fileName The file name.
953    * @param uploadId The Id of upload.
954    * @param existenceAction Checks if an action exists.
955    * @return the response
956    * @throws Exception the exception
957    */
958   protected Response createProcessUploadResponse(String workspaceName,
959                                                  Node currentFolderNode,
960                                                  String siteName,
961                                                  String userId,
962                                                  String jcrPath,
963                                                  String action,
964                                                  String language,
965                                                  String fileName,
966                                                  String uploadId,
967                                                  String existenceAction) throws Exception {
968     if (FileUploadHandler.SAVE_ACTION.equals(action)) {
969       CacheControl cacheControl = new CacheControl();
970       cacheControl.setNoCache(true);
971       return fileUploadHandler.saveAsNTFile(currentFolderNode, uploadId, fileName, language, siteName, userId, existenceAction);
972     }else if(FileUploadHandler.SAVE_NEW_VERSION_ACTION.equals(action)){
973       CacheControl cacheControl = new CacheControl();
974       cacheControl.setNoCache(true);
975       return fileUploadHandler.saveAsNTFile(currentFolderNode, uploadId, fileName, language, siteName, userId, existenceAction,true);
976     }
977     return fileUploadHandler.control(uploadId, action);
978   }
979 
980   /**
981    * Gets the parent folder node.
982    *
983    * @param workspaceName the workspace name
984    * @param driverName the driver name
985    * @param currentFolder the current folder
986    *
987    * @return the parent folder node
988    *
989    * @throws Exception the exception
990    */
991   private Node getParentFolderNode(String workspaceName, String driverName, String currentFolder) throws Exception {
992     SessionProvider sessionProvider = WCMCoreUtils.getUserSessionProvider();
993     ManageableRepository manageableRepository = WCMCoreUtils.getRepository();
994     Session session = sessionProvider.getSession(workspaceName, manageableRepository);
995     ManageDriveService manageDriveService = WCMCoreUtils.getService(ManageDriveService.class);
996     DriveData driveData = manageDriveService.getDriveByName(driverName);
997     String parentPath = (driveData != null ? driveData.getHomePath() : "");
998     NodeHierarchyCreator nodeHierarchyCreator = WCMCoreUtils.getService(NodeHierarchyCreator.class);
999     if(driveData != null &&
1000        driveData.getHomePath().startsWith(nodeHierarchyCreator.getJcrPath(BasePath.CMS_USERS_PATH) + "/${userId}")) {
1001        parentPath = Utils.getPersonalDrivePath(driveData.getHomePath(),
1002                                                ConversationState.getCurrent().getIdentity().getUserId());
1003     };
1004     parentPath += ((currentFolder != null && currentFolder.length() != 0) ? "/" : "") + currentFolder;
1005     parentPath = parentPath.replace("//", "/");
1006     //return result;
1007     return getTargetNode(session, parentPath);
1008   }
1009 
1010   private Node getTargetNode(Session session, String path) throws Exception {
1011     Node node = null;
1012     if (linkManager_ == null) {
1013       linkManager_ = WCMCoreUtils.getService(LinkManager.class);
1014     }
1015     if (nodeFinder_ == null) {
1016       nodeFinder_ = WCMCoreUtils.getService(NodeFinder.class);
1017     }
1018     node = (Node)nodeFinder_.getItem(session, path, true);
1019     return node;
1020   }
1021 
1022   private Element createFolderElement(Document document,
1023                                       Node child,
1024                                       String folderType,
1025                                       String childName,
1026                                       String childCurrentFolder,
1027                                       String nodeDriveName,
1028                                       String type) throws Exception {
1029       Element folder = document.createElement("Folder");
1030 
1031       folder.setAttribute("name", childName.replaceAll("%", "%25"));
1032       folder.setAttribute("title", Utils.getTitle(child).replaceAll("%", "%25"));
1033       folder.setAttribute("url", FCKUtils.createWebdavURL(child));
1034       folder.setAttribute("folderType", folderType);
1035       folder.setAttribute("currentFolder", childCurrentFolder);
1036 
1037       if(TYPE_FOLDER.equals(type) || TYPE_CONTENT.equals(type)) {
1038         boolean hasFolderChild = (getChildOfType(child, NodetypeConstant.NT_UNSTRUCTURED, type) != null)
1039                 || (getChildOfType(child, NodetypeConstant.NT_FOLDER, type) != null);
1040         folder.setAttribute("hasFolderChild", String.valueOf(hasFolderChild));
1041       }else{
1042         folder.setAttribute("hasFolderChild", String.valueOf(this.hasFolderChild(child)));
1043       }
1044       folder.setAttribute("path", child.getPath());
1045       folder.setAttribute("isUpload", "true");
1046       folder.setAttribute("nodeTypeCssClass", Utils.getNodeTypeIcon(child, "uiIcon16x16"));
1047 
1048       if (nodeDriveName!=null && nodeDriveName.length()>0) folder.setAttribute("nodeDriveName", nodeDriveName);
1049       return folder;
1050     }
1051 
1052   /**
1053    * Check isFolder (skip all templateNodetype)
1054    * @param node
1055    * @param childType
1056    * @return
1057    * @throws Exception
1058    */
1059   private Node getChildOfType(Node node, String childType, String type) throws Exception {
1060     TemplateService templateService = WCMCoreUtils.getService(TemplateService.class);
1061     if (node == null) {
1062       return null;
1063     }
1064     NodeIterator iter = node.getNodes();
1065     while (iter.hasNext()) {
1066       Node child = iter.nextNode();
1067       if (!isDocument(child, type) && child.isNodeType(childType)
1068               && !templateService.isManagedNodeType(child.getPrimaryNodeType().getName())
1069               && !"exo:thumbnails".equals(child.getPrimaryNodeType().getName()))
1070       {
1071         return child;
1072       }
1073     }
1074     return null;
1075   }
1076 
1077   /**
1078    * returns a DOMSource object containing given message
1079    * @param message the message
1080    * @return DOMSource object
1081    * @throws Exception
1082    */
1083   private DOMSource createDOMResponse(String message) throws Exception {
1084     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1085     DocumentBuilder builder = factory.newDocumentBuilder();
1086     Document doc = builder.newDocument();
1087     Element rootElement = doc.createElement(message);
1088     doc.appendChild(rootElement);
1089     return new DOMSource(doc);
1090   }
1091 
1092   private static class NodeTitleComparator implements Comparator<Node>{
1093     @Override
1094     public int compare(Node node1, Node node2) {
1095       try{
1096         String titleNode1 = Utils.getTitle(node1);
1097         String titleNode2 = Utils.getTitle(node2);
1098         return titleNode1.compareToIgnoreCase(titleNode2) ;
1099       }catch (Exception e) {
1100         return 0;
1101       }
1102     }
1103   }
1104 
1105   public String getDriveTitle(String name) {
1106     if (name.startsWith(".")) {
1107       String groupLabel = getGroupLabel(name);
1108       if (groupLabel == null) {
1109         groupLabel = getGroupLabel(name, !name.startsWith("/spaces"));
1110       }
1111       return groupLabel;
1112     } else {
1113       return name;
1114     }
1115   }
1116 
1117   public String getGroupLabel(String groupId, boolean isFull) {
1118     String ret = groupId.replace(".", " / ");
1119     if (!isFull) {
1120       if (ret.startsWith(" / spaces")) {
1121         return ret.substring(ret.lastIndexOf("/") + 1).trim();
1122       }
1123       int count = 0;
1124       int slashPosition = -1;
1125       for (int i = 0; i < ret.length(); i++) {
1126         if ('/' == ret.charAt(i)) {
1127           if (++count == 4) {
1128             slashPosition = i;
1129             break;
1130           }
1131         }
1132       }
1133       if (slashPosition > 0) {
1134         ret = ret.substring(0, slashPosition) + "...";
1135       } else if (ret.length() > 70) {
1136         ret = ret.substring(0, 70) + "...";
1137       }
1138     }
1139     return ret;
1140   }
1141 
1142   public String getGroupLabel(String name) {
1143     try {
1144       RepositoryService repoService = WCMCoreUtils.getService(RepositoryService.class);
1145       NodeHierarchyCreator nodeHierarchyCreator = WCMCoreUtils.getService(NodeHierarchyCreator.class);
1146       String groupPath = nodeHierarchyCreator.getJcrPath(BasePath.CMS_GROUPS_PATH);
1147       String absPath = groupPath + name.replace(".", "/");
1148       ManageableRepository currentRepository = repoService.getCurrentRepository();
1149       String workspace = currentRepository.getConfiguration().getDefaultWorkspaceName();
1150 
1151       return getNode(workspace, absPath).getProperty(NodetypeConstant.EXO_LABEL).getString();
1152     } catch (Exception e) {
1153       return null;
1154     }
1155   }
1156 
1157   public Node getNode(String workspace, String absPath) throws Exception {
1158     RepositoryService repoService = WCMCoreUtils.getService(RepositoryService.class);
1159     ManageableRepository currentRepository = repoService.getCurrentRepository();
1160     Node groupNode = (Node) WCMCoreUtils.getSystemSessionProvider().getSession(workspace, currentRepository).getItem(absPath);
1161     return groupNode;
1162   }
1163 
1164 }