Java tutorial
/* * #%L * Alfresco Sharepoint Protocol * %% * Copyright (C) 2005 - 2016 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of * the paid license agreement will prevail. Otherwise, the software is * provided under the following open source license terms: * * Alfresco is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Alfresco is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * #L% */ package org.alfresco.module.vti.handler.alfresco; import java.io.IOException; import java.io.UnsupportedEncodingException; import javax.servlet.http.HttpServletResponse; import org.alfresco.module.vti.handler.DwsException; import org.alfresco.module.vti.metadata.dic.DwsError; import org.alfresco.repo.SessionUser; import org.alfresco.repo.admin.SysAdminParams; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.extensions.surf.util.URLEncoder; /** * Helper class to work with sites through REST API * * @author PavelYur */ public class ShareUtils { private static Log logger = LogFactory.getLog(ShareUtils.class); // constants public static final String HEADER_SET_COOKIE = "Set-Cookie"; public static final String HEADER_CONTENT_TYPE = "Content-Type"; public static final String HEADER_REFERER = "Referer"; public static final String CONTENT_TYPE_JSON = "application/json"; public static final String CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded"; public static final String CONTENT_TYPE_TEXT_PLAIN = "text/plain"; public static final String UTF_8 = "UTF-8"; private SysAdminParams sysAdminParams; public ShareUtils() { } public void setSysAdminParams(SysAdminParams sysAdminParams) { this.sysAdminParams = sysAdminParams; } /** * Get share host with port * * @return host where share application is running */ public String getShareHostWithPort() { return sysAdminParams.getShareProtocol() + "://" + sysAdminParams.getShareHost() + ":" + sysAdminParams.getSharePort(); } private String getAlfrescoContext() { return "/" + sysAdminParams.getAlfrescoContext(); } private String getAlfrescoHostWithPort() { return sysAdminParams.getAlfrescoProtocol() + "://" + sysAdminParams.getAlfrescoHost() + ":" + sysAdminParams.getAlfrescoPort(); } /** * Creates new site using REST API, http method is sent to appropriate web script * * @param user current user * @param sitePreset sitePreset for new site * @param shortName shortName for new site * @param title title for new site * @param description description for new site * @param isPublic is new site public? * @throws HttpException * @throws IOException */ public void createSite(SessionUser user, String sitePreset, String shortName, String title, String description, boolean isPublic) throws HttpException, IOException { HttpClient httpClient = new HttpClient(); title = StringEscapeUtils.escapeJavaScript(title); shortName = StringEscapeUtils.escapeJavaScript(shortName); description = StringEscapeUtils.escapeJavaScript(description); String createSiteBody = "{\"isPublic\":\"" + isPublic + "\",\"title\":\"" + title + "\",\"shortName\":\"" + shortName + "\"," + "\"description\":\"" + description + "\",\"sitePreset\":\"" + sitePreset + "\"" + (isPublic ? ",\"alfresco-createSite-instance-isPublic-checkbox\":\"on\"}" : "}"); PostMethod createSiteMethod = createPostMethod( getAlfrescoHostWithPort() + getAlfrescoContext() + "/s/api/sites?alf_ticket=" + user.getTicket(), createSiteBody, CONTENT_TYPE_JSON); try { if (logger.isDebugEnabled()) logger.debug( "Trying to create site with name: " + shortName + ". URL: " + createSiteMethod.getURI()); int createSiteStatus = httpClient.executeMethod(createSiteMethod); // Check for a critical error if (createSiteStatus != HttpServletResponse.SC_OK) { // There was a problem with the request logger.warn("Site Creation for SPP/Vti failed"); String errorDetails = createSiteMethod.getResponseBodyAsString(); if (logger.isDebugEnabled()) logger.debug("Site creation failure details:\n" + errorDetails); throw new DwsException(DwsError.SERVER_FAILURE); } // Have the response body fetched, to tidy up the HttpClient instance createSiteMethod.getResponseBody(); if (logger.isDebugEnabled()) logger.debug("Create site method returned status: " + createSiteStatus); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Fail to create site with name: " + shortName + ". Message: " + e.getMessage()); if (e instanceof DwsException) { throw (DwsException) e; } throw new RuntimeException(e); } finally { createSiteMethod.releaseConnection(); } // create title sites component createComponent(httpClient, shortName, user, "title", "title/collaboration-title"); // create navigation sites component createComponent(httpClient, shortName, user, "navigation", "navigation/collaboration-navigation"); // create component-1-1 sites component createComponent(httpClient, shortName, user, "component-1-1", "dashlets/site-welcome"); // create component-1-2 sites component createComponent(httpClient, shortName, user, "component-1-2", "dashlets/docsummary"); // create component-2-1 sites component createComponent(httpClient, shortName, user, "component-2-1", "dashlets/site-profile"); // create component-2-2 sites component createComponent(httpClient, shortName, user, "component-2-2", "dashlets/colleagues"); // create documentLibrary folder createDocumentLibrary(httpClient, shortName, user); // create sites dashboard createSiteDashboard(httpClient, shortName, user, sitePreset); // If it's a Document WorkSpace, create Links and Data Lists if ("document-workspace".equalsIgnoreCase(sitePreset)) { // Create the Links Component createLinks(httpClient, shortName, user); } else { // Otherwise create the Calendar createComponent(httpClient, shortName, user, "component-2-3", "dashlets/calendar"); } } /** * Creates site component * * @param httpClient HTTP client * @param siteName name of the site * @param user current user * @param componentName name of the component * @param componentURL URL of the component * @throws UnsupportedEncodingException */ private void createComponent(HttpClient httpClient, String siteName, SessionUser user, String componentName, String componentURL) throws UnsupportedEncodingException { String url = getAlfrescoHostWithPort() + getAlfrescoContext() + "/s/remoteadm/create/alfresco/site-data/components/page." + componentName + ".site~" + siteName + "~dashboard.xml?s=sitestore&alf_ticket=" + user.getTicket(); String body = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<component>\n" + "<guid>page." + componentName + ".site~" + siteName + "~dashboard</guid>\n" + "<scope>page</scope>\n" + "<region-id>" + componentName + "</region-id>\n" + "<source-id>site/" + siteName + "/dashboard</source-id>\n" + "<url>/components/" + componentURL + "</url>\n" + "</component>"; PostMethod postMethod = createPostMethod(url, body, "application/octet-stream"); try { if (logger.isDebugEnabled()) logger.debug("Trying to create site component with name: " + componentName + ". URL: " + postMethod.getURI()); int status = httpClient.executeMethod(postMethod); postMethod.getResponseBody(); if (logger.isDebugEnabled()) logger.debug( "Create component with name: " + componentName + ". Method returned status: " + status); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Fail to create site component with name: " + componentName + ". Message: " + e.getMessage()); throw new RuntimeException(e); } finally { postMethod.releaseConnection(); } } /** * Creates site dashboard * * @param httpClient HTTP client * @param siteName name of the site * @param user current user * @throws UnsupportedEncodingException */ public void createSiteDashboard(HttpClient httpClient, String siteName, SessionUser user, String sitePreset) throws UnsupportedEncodingException { String createSiteDashboardBody = ""; if ("document-workspace".equalsIgnoreCase(sitePreset)) { createSiteDashboardBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<page>\n" + "<title>Document Workspace Dashboard</title>\n" + "<title-id>page.workspace.title</title-id>\n" + "<description>Document Workspace dashboard page</description>\n" + "<description-id>page.workspace.description</description-id>\n" + "<template-instance>dashboard-2-columns-wide-left</template-instance>\n" + "<authentication>user</authentication>\n" + "<properties>\n" + "<sitePages>[ {\"pageId\":\"documentlibrary\"}, {\"pageId\":\"links\"} ]" + "</sitePages>\n" + "</properties>\n" + "</page>"; } else { createSiteDashboardBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<page>\n" + "<title>Meeting Workspace Dashboard</title>\n" + "<title-id>page.meeting_workspace.title</title-id>\n" + "<description>Meeting Workspace dashboard page</description>\n" + "<description-id>page.meeting_workspace.description</description-id>\n" + "<template-instance>dashboard-2-columns-wide-left</template-instance>\n" + "<authentication>user</authentication>\n" + "<properties>\n" + "<sitePages>[ " + "{\"pageId\":\"documentlibrary\"}, {\"pageId\":\"calendar\"} " + "]</sitePages>\n" + "</properties>\n" + "</page>"; } PostMethod createSiteDashboardMethod = createPostMethod( getAlfrescoHostWithPort() + getAlfrescoContext() + "/s/remoteadm/create/alfresco/site-data/pages/site/" + siteName + "/dashboard.xml?s=sitestore&alf_ticket=" + user.getTicket(), createSiteDashboardBody, "application/octet-stream"); try { if (logger.isDebugEnabled()) logger.debug("Trying to create site dashboard. URL: " + createSiteDashboardMethod.getURI()); int status = httpClient.executeMethod(createSiteDashboardMethod); createSiteDashboardMethod.getResponseBody(); if (logger.isDebugEnabled()) logger.debug("Create site dashboard method returned status: " + status); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Fail to create site dashboard. Message: " + e.getMessage()); throw new RuntimeException(e); } finally { createSiteDashboardMethod.releaseConnection(); } } /** * Creates documentLibrary folder in site * * @param httpClient HTTP client * @param siteName short name of site * @param user current user */ private void createDocumentLibrary(HttpClient httpClient, String siteName, SessionUser user) { GetMethod createDocumentLibraryFolderMethod = createGetMethod(getAlfrescoHostWithPort() + getAlfrescoContext() + "/s/slingshot/doclib/doclist/documents/site/" + siteName + "/documentLibrary?filter=recentlyModified&max=10&alf_ticket=" + user.getTicket()); try { if (logger.isDebugEnabled()) logger.debug("Trying to create sites documentLibrary folder. URL: " + createDocumentLibraryFolderMethod.getURI()); int status = httpClient.executeMethod(createDocumentLibraryFolderMethod); createDocumentLibraryFolderMethod.getResponseBody(); if (logger.isDebugEnabled()) logger.debug("Create sites documentLibrary folder method returned status: " + status); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Fail to create sites documentLibrary folder. Message: " + e.getMessage()); throw new RuntimeException(e); } finally { createDocumentLibraryFolderMethod.releaseConnection(); } } /** * Creates links folder in site * * @param httpClient HTTP client * @param siteName short name of site * @param user current user */ private void createLinks(HttpClient httpClient, String siteName, SessionUser user) { GetMethod createLinksFolderMethod = createGetMethod(getAlfrescoHostWithPort() + getAlfrescoContext() + "/s/api/links/site/" + siteName + "/links?page=1&pageSize=1&alf_ticket=" + user.getTicket()); try { if (logger.isDebugEnabled()) logger.debug("Trying to create site links folder. URL: " + createLinksFolderMethod.getURI()); int status = httpClient.executeMethod(createLinksFolderMethod); createLinksFolderMethod.getResponseBody(); if (logger.isDebugEnabled()) logger.debug("Create site links folder method returned status: " + status); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Fail to create site links folder. Message: " + e.getMessage()); throw new RuntimeException(e); } finally { createLinksFolderMethod.releaseConnection(); } } /** * Creates the Data Lists folder in site * * @param httpClient HTTP client * @param siteName short name of site * @param user current user */ private void createDataLists(HttpClient httpClient, String siteName, SessionUser user) { GetMethod createDataListsFolderMethod = createGetMethod( getAlfrescoHostWithPort() + getAlfrescoContext() + "/s/slingshot/datalists/lists/site/" + siteName + "/dataLists?page=1&pageSize=1&alf_ticket=" + user.getTicket()); try { if (logger.isDebugEnabled()) logger.debug( "Trying to create site Data Lists folder. URL: " + createDataListsFolderMethod.getURI()); int status = httpClient.executeMethod(createDataListsFolderMethod); createDataListsFolderMethod.getResponseBody(); if (logger.isDebugEnabled()) logger.debug("Create site Data Lists folder method returned status: " + status); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Fail to create site Data Lists folder. Message: " + e.getMessage()); throw new RuntimeException(e); } finally { createDataListsFolderMethod.releaseConnection(); } } /** * Creates POST method * * @param url URL for request * @param body body of request * @param contentType content type of request * @return POST method * @throws UnsupportedEncodingException */ private PostMethod createPostMethod(String url, String body, String contentType) throws UnsupportedEncodingException { PostMethod postMethod = new PostMethod(url); postMethod.setRequestHeader(HEADER_CONTENT_TYPE, contentType); postMethod.setRequestEntity(new StringRequestEntity(body, CONTENT_TYPE_TEXT_PLAIN, UTF_8)); return postMethod; } /** * Creates GET method * * @param url URL for request * @return GET method */ private GetMethod createGetMethod(String url) { GetMethod getMethod = new GetMethod(url); return getMethod; } /** * Deletes site using REST API, http method is sent to appropriate web script * * @param user current user * @param shortName shortName of site we are going to delete * @throws HttpException * @throws IOException */ public void deleteSite(SessionUser user, String shortName) throws HttpException, IOException { HttpClient httpClient = new HttpClient(); DeleteMethod deleteSiteMethod = new DeleteMethod(getAlfrescoHostWithPort() + getAlfrescoContext() + "/s/api/sites/" + shortName + "?alf_ticket=" + user.getTicket()); try { if (logger.isDebugEnabled()) logger.debug("Trying to delete site with name: " + shortName); int status = httpClient.executeMethod(deleteSiteMethod); if (logger.isDebugEnabled()) logger.debug("Delete site method returned status: " + status); if (status != HttpStatus.SC_OK) { throw new RuntimeException( "Failed to delete site with name: " + shortName + ". Returned status is: " + status + ". \n Response from server :\n" + deleteSiteMethod.getResponseBodyAsString()); } deleteSiteMethod.getResponseBody(); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Fail to delete site with name: " + shortName); throw new RuntimeException(e); } finally { deleteSiteMethod.releaseConnection(); } // deletes site dashboard deleteSiteDashboard(httpClient, shortName, user); // deletes title component deleteSiteComponent(httpClient, shortName, user, "title"); // deletes navigation component deleteSiteComponent(httpClient, shortName, user, "navigation"); // deletes component-2-2 component deleteSiteComponent(httpClient, shortName, user, "component-2-2"); // deletes component-1-1 component deleteSiteComponent(httpClient, shortName, user, "component-1-1"); // deletes component-2-1 component deleteSiteComponent(httpClient, shortName, user, "component-2-1"); // deletes component-1-2 component deleteSiteComponent(httpClient, shortName, user, "component-1-2"); } /** * Deletes component from site * * @param httpClient HTTP client * @param siteName name of the site * @param user current user * @param componentName name of the component */ private void deleteSiteComponent(HttpClient httpClient, String siteName, SessionUser user, String componentName) { DeleteMethod deleteTitleMethod = new DeleteMethod(getAlfrescoHostWithPort() + getAlfrescoContext() + "/s/remoteadm/delete/alfresco/site-data/components/page." + componentName + ".site~" + siteName + "~dashboard.xml?s=sitestore&alf_ticket=" + user.getTicket()); try { if (logger.isDebugEnabled()) logger.debug("Trying to delete site component with name: " + siteName); int status = httpClient.executeMethod(deleteTitleMethod); deleteTitleMethod.getResponseBody(); if (logger.isDebugEnabled()) logger.debug("Delete site component method returned status: " + status); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Fail to delete component from site with name: " + siteName); throw new RuntimeException(e); } finally { deleteTitleMethod.releaseConnection(); } } /** * Deletes site dashboard * * @param httpClient HTTP client * @param siteName name of the site * @param user current user */ private void deleteSiteDashboard(HttpClient httpClient, String siteName, SessionUser user) { DeleteMethod deleteDashboardMethod = new DeleteMethod(getAlfrescoHostWithPort() + getAlfrescoContext() + "/s/remoteadm/delete/alfresco/site-data/pages/site/" + siteName + "/dashboard.xml?s=sitestore&alf_ticket=" + user.getTicket()); try { if (logger.isDebugEnabled()) logger.debug("Trying to delete dashboard from site with name: " + siteName); int status = httpClient.executeMethod(deleteDashboardMethod); deleteDashboardMethod.getResponseBody(); if (logger.isDebugEnabled()) logger.debug("Delete dashboard from site method returned status: " + status); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Fail to delete dashboard from site with name: " + siteName); throw new RuntimeException(e); } finally { deleteDashboardMethod.releaseConnection(); } } /** * Get share context name * * @return String share context name */ public String getShareContext() { return "/" + sysAdminParams.getShareContext(); } /** * <p> * encode string to share specific manner (all characters with code > 127 will be encoded in %u0... format) * </p> * * @param value to encode * @return encoded value * @throws UnsupportedEncodingException */ public static String encode(String value) throws UnsupportedEncodingException { StringBuilder result = new StringBuilder(value.length()); for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); if (c > 127) { result.append("%u0" + Integer.toHexString(c).toUpperCase()); } else { if (c > 'a' && c < 'z' || c > 'A' && c < 'Z' || c == '/' || c == '@' || c == '+') { result.append(c); } else { result.append(URLEncoder.encode(c + "")); } } } return result.toString(); } }