View Javadoc
1   /*
2    * Copyright (C) 2003-2009 eXo Platform SAS.
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.io.OutputStreamWriter;
20  import java.net.URL;
21  import java.net.URLConnection;
22  import java.text.DateFormat;
23  import java.text.SimpleDateFormat;
24  import java.util.ArrayList;
25  import java.util.Date;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.MissingResourceException;
29  import java.util.Random;
30  import java.util.ResourceBundle;
31  
32  import javax.ws.rs.GET;
33  import javax.ws.rs.Path;
34  import javax.ws.rs.QueryParam;
35  import javax.ws.rs.core.CacheControl;
36  import javax.ws.rs.core.MediaType;
37  import javax.ws.rs.core.Response;
38  import javax.xml.parsers.DocumentBuilder;
39  import javax.xml.parsers.DocumentBuilderFactory;
40  import javax.xml.transform.dom.DOMSource;
41  
42  import org.apache.commons.io.IOUtils;
43  import org.exoplatform.application.gadget.Gadget;
44  import org.exoplatform.application.gadget.GadgetRegistryService;
45  import org.exoplatform.application.registry.Application;
46  import org.exoplatform.application.registry.ApplicationCategory;
47  import org.exoplatform.application.registry.ApplicationRegistryService;
48  import org.exoplatform.container.PortalContainer;
49  import org.exoplatform.container.component.RequestLifeCycle;
50  import org.exoplatform.container.xml.InitParams;
51  import org.exoplatform.portal.config.model.ApplicationType;
52  import org.exoplatform.portal.gadget.core.ExoDefaultSecurityTokenGenerator;
53  import org.exoplatform.services.log.ExoLogger;
54  import org.exoplatform.services.log.Log;
55  import org.exoplatform.services.rest.resource.ResourceContainer;
56  import org.exoplatform.services.security.ConversationState;
57  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
58  import org.json.JSONObject;
59  import org.w3c.dom.Document;
60  import org.w3c.dom.Element;
61  
62  /**
63   * Instantiates a new gadget connector.
64   *
65   * @LevelAPI Provisional
66   * 
67   * @anchor GadgetConnector
68   */
69  @Path("/wcmGadget/")
70  public class GadgetConnector extends ExoDefaultSecurityTokenGenerator implements ResourceContainer {
71  
72    /** The Constant FCK_RESOURCE_BUNDLE_FILE. */
73    public static final String         FCK_RESOURCE_BUNDLE_FILE      = "locale.services.fckeditor.FCKConnector";
74  
75    /** The application registry service. */
76    private ApplicationRegistryService applicationRegistryService;
77  
78    /** The gadget registry service. */
79    private GadgetRegistryService gadgetRegistryService;
80  
81    /** The Constant LAST_MODIFIED_PROPERTY. */
82    private static final String LAST_MODIFIED_PROPERTY = "Last-Modified";
83  
84    /** The Constant IF_MODIFIED_SINCE_DATE_FORMAT. */
85    private static final String IF_MODIFIED_SINCE_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z";
86  
87    /** The log. */
88    private static final Log LOG = ExoLogger.getLogger(GadgetConnector.class.getName());
89  
90    /**
91     * Instantiates a new gadget connector.
92     *
93     * @param initParams the init params.
94     */
95    public GadgetConnector(InitParams initParams) throws Exception {
96      applicationRegistryService = WCMCoreUtils.getService(ApplicationRegistryService.class);
97      gadgetRegistryService = WCMCoreUtils.getService(GadgetRegistryService.class);
98    }
99  
100   /**
101    * Gets folders and files.
102    *
103    * @param currentFolder The current folder.
104    * @param lang The language.
105    * @param host The server address on which the gadget is deployed.
106    * @return The folders and files.
107    * @throws Exception The exception
108    * 
109    * @anchor GadgetConnector.getFoldersAndFiles
110    */
111   @GET
112   @Path("/getFoldersAndFiles/")
113   public Response getFoldersAndFiles(@QueryParam("currentFolder") String currentFolder,
114                                      @QueryParam("lang") String lang,
115                                      @QueryParam("host") String host) throws Exception {
116     try {
117       Response response = buildXMLResponse(currentFolder, lang, host);
118       if (response != null)
119         return response;
120     } catch (Exception e) {
121       if (LOG.isErrorEnabled()) {
122         LOG.error("Error when perform getFoldersAndFiles: ", e);
123       }
124     }
125     DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
126     return Response.ok().header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date())).build();
127   }
128 
129   /**
130    * Builds the XML response.
131    *
132    * @param currentFolder The current folder.
133    * @param language The language.
134    * @param host The server address on which the gadget is deployed.
135    *
136    * @return the response
137    *
138    * @throws Exception the exception
139    */
140   public Response buildXMLResponse(String currentFolder, String language, String host) throws Exception {
141     List<ApplicationCategory> applicationCategories = getGadgetCategories();
142     Element rootElement = createRootElement(currentFolder, applicationCategories, language, host);
143     Document document = rootElement.getOwnerDocument();
144     CacheControl cacheControl = new CacheControl();
145     cacheControl.setNoCache(true);
146     cacheControl.setNoStore(true);
147     DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
148     return Response.ok(new DOMSource(document), MediaType.TEXT_XML)
149                    .cacheControl(cacheControl)
150                    .header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date()))
151                    .build();
152   }
153 
154   /**
155    * Creates the root element.
156    *
157    * @param currentFolder The current folder.
158    * @param applicationCategories The application categories.
159    * @param language The language.
160    *
161    * @return The element
162    *
163    * @throws Exception the exception
164    */
165   private Element createRootElement(String currentFolder,
166                                     List<ApplicationCategory> applicationCategories,
167                                     String language,
168                                     String host) throws Exception {
169     Document document = null;
170     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
171     DocumentBuilder builder = factory.newDocumentBuilder();
172     document = builder.newDocument();
173     if (applicationCategories.isEmpty()) {
174       Locale locale = null;
175       if (language == null) {
176         locale = Locale.ENGLISH;
177       } else {
178         locale = new Locale(language);
179       }
180       ResourceBundle resourceBundle = ResourceBundle.getBundle(FCK_RESOURCE_BUNDLE_FILE, locale);
181       String message = "";
182       try {
183         message = resourceBundle.getString("fckeditor.no-gadget");
184       } catch (MissingResourceException e) {
185         message = "fckeditor.no-gadget";
186       }
187       Element rootElement = document.createElement("Message");
188       document.appendChild(rootElement);
189       rootElement.setAttribute("number", "555");
190       rootElement.setAttribute("text", message);
191       rootElement.setAttribute("type", "Error");
192       return rootElement;
193     }
194     Element rootElement = document.createElement("Connector");
195     document.appendChild(rootElement);
196     rootElement.setAttribute("resourceType", "Gadget");
197     Element currentFolderElement = document.createElement("CurrentFolder");
198     if (currentFolder == null || currentFolder.equals("/")){
199       currentFolderElement.setAttribute("name", applicationCategories.get(0).getName());
200       Element foldersElement = createFolderElement(document, applicationCategories);
201       rootElement.appendChild(foldersElement);
202     } else {
203       PortalContainer container = PortalContainer.getInstance();
204       RequestLifeCycle.begin(container);
205       try {
206         ApplicationCategory applicationCategory = applicationRegistryService
207             .getApplicationCategory(currentFolder.substring(1, currentFolder.length() - 1));
208         currentFolderElement.setAttribute("name", applicationCategory.getDisplayName());
209         Element filesElement = createFileElement(document, applicationCategory, host);
210         rootElement.appendChild(filesElement);
211       } finally {
212         RequestLifeCycle.end();
213       }
214     }
215     rootElement.appendChild(currentFolderElement);
216     return rootElement;
217   }
218 
219   /**
220    * Creates the folder element.
221    *
222    * @param document The document.
223    * @param applicationCategories The application categories.
224    *
225    * @return The element
226    *
227    * @throws Exception the exception
228    */
229   private Element createFolderElement(Document document,
230                                       List<ApplicationCategory> applicationCategories) throws Exception {
231     Element folders = document.createElement("Folders");
232     for (ApplicationCategory applicationCategory : applicationCategories) {
233       Element folder = document.createElement("Folder");
234       folder.setAttribute("name", applicationCategory.getDisplayName());
235       folders.appendChild(folder);
236     }
237     return folders;
238   }
239 
240   /**
241    * Creates the file element.
242    *
243    * @param document The document.
244    * @param applicationCategory The application category.
245    *
246    * @return the element
247    *
248    * @throws Exception the exception
249    */
250   private Element createFileElement(Document document,
251                                     ApplicationCategory applicationCategory,
252                                     String host) throws Exception {
253     Element files = document.createElement("Files");
254     List<Application> listApplication = applicationRegistryService.getApplications(applicationCategory,
255                                                                                    ApplicationType.GADGET);
256     for (Application application : listApplication) {
257       Gadget gadget = gadgetRegistryService.getGadget(application.getApplicationName());
258       Element file = document.createElement("File");
259       file.setAttribute("name", gadget.getName());
260       file.setAttribute("fileType", "nt_unstructured");
261       file.setAttribute("size", "0");
262       file.setAttribute("thumbnail", gadget.getThumbnail());
263       file.setAttribute("description", gadget.getDescription());
264 
265       String fullurl = "";
266       if (gadget.isLocal()) {
267         fullurl = "/" + PortalContainer.getCurrentRestContextName() + "/" + gadget.getUrl();
268       } else {
269         fullurl = gadget.getUrl();
270       }
271       file.setAttribute("url", fullurl);
272 
273       String data = "{\"context\":{\"country\":\"US\",\"language\":\"en\"},\"gadgets\":[{\"moduleId\":0,\"url\":\""
274           + fullurl + "\",\"prefs\":[]}]}";
275       URL url = new URL(host + "/eXoGadgetServer/gadgets/metadata");
276       URLConnection conn = url.openConnection();
277       conn.setDoOutput(true);
278       OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
279       wr.write(data);
280       wr.flush();
281       String strMetadata = IOUtils.toString(conn.getInputStream(), "UTF-8");
282       wr.close();
283       JSONObject metadata = new JSONObject(strMetadata.toString());
284 
285       ConversationState conversationState = ConversationState.getCurrent();
286       String userId = conversationState.getIdentity().getUserId();
287       String token = createToken(gadget.getUrl(), userId, userId, new Random().nextLong(), "default");
288       JSONObject obj = metadata.getJSONArray("gadgets").getJSONObject(0);
289       obj.put("secureToken", token);
290 
291       file.setAttribute("metadata", metadata.toString());
292       files.appendChild(file);
293     }
294     return files;
295   }
296 
297   /**
298    * Gets the gadget categories.
299    *
300    * @return The gadget categories.
301    *
302    * @throws Exception the exception
303    */
304   private List<ApplicationCategory> getGadgetCategories() throws Exception {
305     List<ApplicationCategory> gadgetCategories = new ArrayList<ApplicationCategory>();
306     PortalContainer container = PortalContainer.getInstance();
307     RequestLifeCycle.begin(container);
308     try {
309       List<ApplicationCategory> applicationCategories = applicationRegistryService.getApplicationCategories();
310       for (ApplicationCategory applicationCategory : applicationCategories) {
311         if (!applicationRegistryService.getApplications(applicationCategory, ApplicationType.GADGET)
312                                        .isEmpty()) {
313           gadgetCategories.add(applicationCategory);
314         }
315       }
316     } finally {
317       RequestLifeCycle.end();
318     }
319     return gadgetCategories;
320   }
321 }