001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.dynamicdatamapping.lar;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.lar.BasePortletDataHandler;
019    import com.liferay.portal.kernel.lar.PortletDataContext;
020    import com.liferay.portal.kernel.lar.PortletDataHandlerBoolean;
021    import com.liferay.portal.kernel.lar.PortletDataHandlerControl;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.util.FileUtil;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.LocaleUtil;
027    import com.liferay.portal.kernel.util.LocalizationUtil;
028    import com.liferay.portal.kernel.util.MapUtil;
029    import com.liferay.portal.kernel.util.StringBundler;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.Validator;
032    import com.liferay.portal.kernel.xml.Document;
033    import com.liferay.portal.kernel.xml.Element;
034    import com.liferay.portal.kernel.xml.SAXReaderUtil;
035    import com.liferay.portal.model.Image;
036    import com.liferay.portal.service.ServiceContext;
037    import com.liferay.portal.service.UserLocalServiceUtil;
038    import com.liferay.portal.service.persistence.ImageUtil;
039    import com.liferay.portal.util.PortalUtil;
040    import com.liferay.portal.util.PortletKeys;
041    import com.liferay.portlet.dynamicdatamapping.TemplateDuplicateTemplateKeyException;
042    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
043    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
044    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
045    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
046    import com.liferay.portlet.dynamicdatamapping.service.persistence.DDMStructureUtil;
047    import com.liferay.portlet.dynamicdatamapping.service.persistence.DDMTemplateUtil;
048    
049    import java.io.File;
050    
051    import java.util.List;
052    import java.util.Locale;
053    import java.util.Map;
054    
055    import javax.portlet.PortletPreferences;
056    
057    /**
058     * @author Marcellus Tavares
059     */
060    public class DDMPortletDataHandlerImpl extends BasePortletDataHandler {
061    
062            public static void exportStructure(
063                            PortletDataContext portletDataContext, Element structuresElement,
064                            DDMStructure structure)
065                    throws Exception {
066    
067                    String path = getStructurePath(portletDataContext, structure);
068    
069                    if (!portletDataContext.isPathNotProcessed(path)) {
070                            return;
071                    }
072    
073                    Element structureElement = structuresElement.addElement("structure");
074    
075                    long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
076                            structure.getCompanyId());
077    
078                    if (defaultUserId == structure.getUserId()) {
079                            structureElement.addAttribute("preloaded", "true");
080                    }
081    
082                    portletDataContext.addClassedModel(
083                            structureElement, path, structure, _NAMESPACE);
084            }
085    
086            public static void exportTemplate(
087                            PortletDataContext portletDataContext, Element templatesElement,
088                            DDMTemplate template)
089                    throws Exception {
090    
091                    String path = getTemplatePath(portletDataContext, template);
092    
093                    exportTemplate(portletDataContext, templatesElement, path, template);
094            }
095    
096            public static void exportTemplate(
097                            PortletDataContext portletDataContext, Element templatesElement,
098                            String path, DDMTemplate template)
099                    throws Exception {
100    
101                    if (!portletDataContext.isPathNotProcessed(path)) {
102                            return;
103                    }
104    
105                    // Clone this template to make sure changes to its content are never
106                    // persisted
107    
108                    template = (DDMTemplate)template.clone();
109    
110                    Element templateElement = templatesElement.addElement("template");
111    
112                    if (template.isSmallImage() &&
113                            Validator.isNull(template.getSmallImageURL())) {
114    
115                            Image smallImage = ImageUtil.fetchByPrimaryKey(
116                                    template.getSmallImageId());
117    
118                            if (smallImage != null) {
119                                    String smallImagePath = getTemplateSmallImagePath(
120                                            portletDataContext, template);
121    
122                                    templateElement.addAttribute(
123                                            "small-image-path", smallImagePath);
124    
125                                    template.setSmallImageType(smallImage.getType());
126    
127                                    portletDataContext.addZipEntry(
128                                            smallImagePath, smallImage.getTextObj());
129                            }
130                    }
131    
132                    portletDataContext.addClassedModel(
133                            templateElement, path, template, _NAMESPACE);
134            }
135    
136            public static void importStructure(
137                            PortletDataContext portletDataContext, Element structureElement)
138                    throws Exception {
139    
140                    String path = structureElement.attributeValue("path");
141    
142                    if (!portletDataContext.isPathNotProcessed(path)) {
143                            return;
144                    }
145    
146                    DDMStructure structure =
147                            (DDMStructure)portletDataContext.getZipEntryAsObject(
148                                    structureElement, path);
149    
150                    prepareLanguagesForImport(structure);
151    
152                    long userId = portletDataContext.getUserId(structure.getUserUuid());
153    
154                    Map<Long, Long> structureIds =
155                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
156                                    DDMStructure.class);
157    
158                    ServiceContext serviceContext = portletDataContext.createServiceContext(
159                            structureElement, structure, _NAMESPACE);
160    
161                    DDMStructure importedStructure = null;
162    
163                    if (portletDataContext.isDataStrategyMirror()) {
164                            boolean preloaded = GetterUtil.getBoolean(
165                                    structureElement.attributeValue("preloaded"));
166    
167                            DDMStructure existingStructure = null;
168    
169                            if (!preloaded) {
170                                    existingStructure = DDMStructureUtil.fetchByUUID_G(
171                                            structure.getUuid(), portletDataContext.getScopeGroupId());
172                            }
173                            else {
174                                    existingStructure = DDMStructureUtil.fetchByG_S(
175                                            portletDataContext.getScopeGroupId(),
176                                            structure.getStructureKey());
177                            }
178    
179                            if (existingStructure == null) {
180                                    serviceContext.setUuid(structure.getUuid());
181    
182                                    importedStructure = DDMStructureLocalServiceUtil.addStructure(
183                                            userId, portletDataContext.getScopeGroupId(),
184                                            structure.getParentStructureId(),
185                                            structure.getClassNameId(), structure.getStructureKey(),
186                                            structure.getNameMap(), structure.getDescriptionMap(),
187                                            structure.getXsd(), structure.getStorageType(),
188                                            structure.getType(), serviceContext);
189                            }
190                            else {
191                                    importedStructure =
192                                            DDMStructureLocalServiceUtil.updateStructure(
193                                                    existingStructure.getStructureId(),
194                                                    structure.getParentStructureId(),
195                                                    structure.getNameMap(), structure.getDescriptionMap(),
196                                                    structure.getXsd(), serviceContext);
197                            }
198                    }
199                    else {
200                            importedStructure = DDMStructureLocalServiceUtil.addStructure(
201                                    userId, portletDataContext.getScopeGroupId(),
202                                    structure.getParentStructureId(), structure.getClassNameId(),
203                                    structure.getStructureKey(), structure.getNameMap(),
204                                    structure.getDescriptionMap(), structure.getXsd(),
205                                    structure.getStorageType(), structure.getType(),
206                                    serviceContext);
207                    }
208    
209                    portletDataContext.importClassedModel(
210                            structure, importedStructure, _NAMESPACE);
211    
212                    structureIds.put(
213                            structure.getStructureId(), importedStructure.getStructureId());
214            }
215    
216            public static void importTemplate(
217                            PortletDataContext portletDataContext, Element templateElement)
218                    throws Exception {
219    
220                    String path = templateElement.attributeValue("path");
221    
222                    if (!portletDataContext.isPathNotProcessed(path)) {
223                            return;
224                    }
225    
226                    DDMTemplate template =
227                            (DDMTemplate)portletDataContext.getZipEntryAsObject(
228                                    templateElement, path);
229    
230                    long userId = portletDataContext.getUserId(template.getUserUuid());
231    
232                    Map<Long, Long> structureIds =
233                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
234                                    DDMStructure.class);
235    
236                    long classPK = MapUtil.getLong(
237                            structureIds, template.getClassPK(), template.getClassPK());
238    
239                    File smallFile = null;
240    
241                    String smallImagePath = templateElement.attributeValue(
242                            "small-image-path");
243    
244                    if (template.isSmallImage() && Validator.isNotNull(smallImagePath)) {
245                            byte[] bytes = portletDataContext.getZipEntryAsByteArray(
246                                    smallImagePath);
247    
248                            if (bytes != null) {
249                                    smallFile = FileUtil.createTempFile(
250                                            template.getSmallImageType());
251    
252                                    FileUtil.write(smallFile, bytes);
253                            }
254                    }
255    
256                    ServiceContext serviceContext = portletDataContext.createServiceContext(
257                            templateElement, template, _NAMESPACE);
258    
259                    DDMTemplate importedTemplate = null;
260    
261                    if (portletDataContext.isDataStrategyMirror()) {
262                            DDMTemplate existingTemplate = DDMTemplateUtil.fetchByUUID_G(
263                                    template.getUuid(), portletDataContext.getScopeGroupId());
264    
265                            if (existingTemplate == null) {
266                                    serviceContext.setUuid(template.getUuid());
267    
268                                    importedTemplate = addTemplate(
269                                            userId, portletDataContext.getScopeGroupId(), template,
270                                            classPK, smallFile, serviceContext);
271                            }
272                            else {
273                                    importedTemplate = DDMTemplateLocalServiceUtil.updateTemplate(
274                                            existingTemplate.getTemplateId(), template.getNameMap(),
275                                            template.getDescriptionMap(), template.getType(),
276                                            template.getMode(), template.getLanguage(),
277                                            template.getScript(), template.isCacheable(),
278                                            template.isSmallImage(), template.getSmallImageURL(),
279                                            smallFile, serviceContext);
280                            }
281                    }
282                    else {
283                            importedTemplate = addTemplate(
284                                    userId, portletDataContext.getScopeGroupId(), template, classPK,
285                                    smallFile, serviceContext);
286                    }
287    
288                    portletDataContext.importClassedModel(
289                            template, importedTemplate, _NAMESPACE);
290            }
291    
292            @Override
293            public PortletDataHandlerControl[] getExportControls() {
294                    return new PortletDataHandlerControl[] {_structures, _templates};
295            }
296    
297            @Override
298            public PortletDataHandlerControl[] getImportControls() {
299                    return new PortletDataHandlerControl[] {_structures, _templates};
300            }
301    
302            @Override
303            public boolean isAlwaysExportable() {
304                    return _ALWAYS_EXPORTABLE;
305            }
306    
307            @Override
308            public boolean isDataLocalized() {
309                    return _DATA_LOCALIZED;
310            }
311    
312            protected static DDMTemplate addTemplate(
313                            long userId, long groupId, DDMTemplate template, long classPK,
314                            File smallFile, ServiceContext serviceContext)
315                    throws Exception {
316    
317                    DDMTemplate newTemplate = null;
318    
319                    try {
320                            return DDMTemplateLocalServiceUtil.addTemplate(
321                                    userId, groupId, template.getClassNameId(), classPK,
322                                    template.getTemplateKey(), template.getNameMap(),
323                                    template.getDescriptionMap(), template.getType(),
324                                    template.getMode(), template.getLanguage(),
325                                    template.getScript(), template.isCacheable(),
326                                    template.isSmallImage(), template.getSmallImageURL(), smallFile,
327                                    serviceContext);
328                    }
329                    catch (TemplateDuplicateTemplateKeyException tdtke) {
330                            newTemplate = DDMTemplateLocalServiceUtil.addTemplate(
331                                    userId, groupId, template.getClassNameId(), classPK, null,
332                                    template.getNameMap(), template.getDescriptionMap(),
333                                    template.getType(), template.getMode(), template.getLanguage(),
334                                    template.getScript(), template.isCacheable(),
335                                    template.isSmallImage(), template.getSmallImageURL(), smallFile,
336                                    serviceContext);
337    
338                            if (_log.isWarnEnabled()) {
339                                    _log.warn(
340                                            "A template with the key " + template.getTemplateKey() +
341                                                    " already exists. The new generated key is " +
342                                                            newTemplate.getTemplateKey());
343                            }
344                    }
345    
346                    return newTemplate;
347            }
348    
349            protected static String getStructurePath(
350                    PortletDataContext portletDataContext, DDMStructure structure) {
351    
352                    StringBundler sb = new StringBundler(4);
353    
354                    sb.append(
355                            portletDataContext.getPortletPath(
356                                    PortletKeys.DYNAMIC_DATA_MAPPING));
357                    sb.append("/structures/");
358                    sb.append(structure.getStructureId());
359                    sb.append(".xml");
360    
361                    return sb.toString();
362            }
363    
364            protected static String getTemplatePath(
365                    PortletDataContext portletDataContext, DDMTemplate template) {
366    
367                    StringBundler sb = new StringBundler(4);
368    
369                    sb.append(
370                            portletDataContext.getPortletPath(
371                                    PortletKeys.DYNAMIC_DATA_MAPPING));
372                    sb.append("/templates/");
373                    sb.append(template.getTemplateId());
374                    sb.append(".xml");
375    
376                    return sb.toString();
377            }
378    
379            protected static String getTemplateSmallImagePath(
380                            PortletDataContext portletDataContext, DDMTemplate template)
381                    throws Exception {
382    
383                    StringBundler sb = new StringBundler(5);
384    
385                    sb.append(
386                            portletDataContext.getPortletPath(
387                                    PortletKeys.DYNAMIC_DATA_MAPPING));
388                    sb.append("/templates/thumbnail-");
389                    sb.append(template.getTemplateId());
390                    sb.append(StringPool.PERIOD);
391                    sb.append(template.getSmallImageType());
392    
393                    return sb.toString();
394            }
395    
396            protected static void prepareLanguagesForImport(DDMStructure structure)
397                    throws PortalException {
398    
399                    Locale structureDefaultLocale = LocaleUtil.fromLanguageId(
400                            structure.getDefaultLanguageId());
401    
402                    Locale[] structureAvailableLocales = LocaleUtil.fromLanguageIds(
403                            structure.getAvailableLanguageIds());
404    
405                    Locale defaultImportLocale = LocalizationUtil.getDefaultImportLocale(
406                            DDMStructure.class.getName(), structure.getPrimaryKey(),
407                            structureDefaultLocale, structureAvailableLocales);
408    
409                    structure.prepareLocalizedFieldsForImport(defaultImportLocale);
410            }
411    
412            @Override
413            protected PortletPreferences doDeleteData(
414                            PortletDataContext portletDataContext, String portletId,
415                            PortletPreferences portletPreferences)
416                    throws Exception {
417    
418                    if (!portletDataContext.addPrimaryKey(
419                                    DDMPortletDataHandlerImpl.class, "deleteData")) {
420    
421                            DDMTemplateLocalServiceUtil.deleteTemplates(
422                                    portletDataContext.getScopeGroupId());
423    
424                            DDMStructureLocalServiceUtil.deleteStructures(
425                                    portletDataContext.getScopeGroupId());
426                    }
427    
428                    return portletPreferences;
429            }
430    
431            @Override
432            protected String doExportData(
433                            PortletDataContext portletDataContext, String portletId,
434                            PortletPreferences portletPreferences)
435                    throws Exception {
436    
437                    portletDataContext.addPermissions(
438                            "com.liferay.portlet.dynamicdatamapping",
439                            portletDataContext.getScopeGroupId());
440    
441                    Document document = SAXReaderUtil.createDocument();
442    
443                    Element rootElement = document.addElement("ddm-data");
444    
445                    rootElement.addAttribute(
446                            "group-id", String.valueOf(portletDataContext.getScopeGroupId()));
447    
448                    Element structuresElement = rootElement.addElement("structures");
449    
450                    List<DDMStructure> ddmStructures = DDMStructureUtil.findByGroupId(
451                            portletDataContext.getScopeGroupId());
452    
453                    for (DDMStructure structure : ddmStructures) {
454                            if (portletDataContext.isWithinDateRange(
455                                            structure.getModifiedDate())) {
456    
457                                    exportStructure(
458                                            portletDataContext, structuresElement, structure);
459                            }
460                    }
461    
462                    Element templatesElement = rootElement.addElement("templates");
463    
464                    if (portletDataContext.getBooleanParameter(_NAMESPACE, "templates")) {
465                            List<DDMTemplate> templates = DDMTemplateUtil.findByG_C(
466                                    portletDataContext.getScopeGroupId(),
467                                    PortalUtil.getClassNameId(DDMStructure.class));
468    
469                            for (DDMTemplate template : templates) {
470                                    if (portletDataContext.isWithinDateRange(
471                                                    template.getModifiedDate())) {
472    
473                                            exportTemplate(
474                                                    portletDataContext, templatesElement, template);
475                                    }
476                            }
477                    }
478    
479                    return document.formattedString();
480            }
481    
482            @Override
483            protected PortletPreferences doImportData(
484                            PortletDataContext portletDataContext, String portletId,
485                            PortletPreferences portletPreferences, String data)
486                    throws Exception {
487    
488                    portletDataContext.importPermissions(
489                            "com.liferay.portlet.dynamicdatamapping",
490                            portletDataContext.getSourceGroupId(),
491                            portletDataContext.getScopeGroupId());
492    
493                    Document document = SAXReaderUtil.read(data);
494    
495                    Element rootElement = document.getRootElement();
496    
497                    Element structuresElement = rootElement.element("structures");
498    
499                    List<Element> structureElements = structuresElement.elements(
500                            "structure");
501    
502                    for (Element structureElement : structureElements) {
503                            importStructure(portletDataContext, structureElement);
504                    }
505    
506                    if (portletDataContext.getBooleanParameter(_NAMESPACE, "templates")) {
507                            Element templatesElement = rootElement.element("templates");
508    
509                            List<Element> templateElements = templatesElement.elements(
510                                    "template");
511    
512                            for (Element templateElement : templateElements) {
513                                    importTemplate(portletDataContext, templateElement);
514                            }
515                    }
516    
517                    return portletPreferences;
518            }
519    
520            private static final boolean _ALWAYS_EXPORTABLE = true;
521    
522            private static final boolean _DATA_LOCALIZED = true;
523    
524            private static final String _NAMESPACE = "ddm";
525    
526            private static Log _log = LogFactoryUtil.getLog(
527                    DDMPortletDataHandlerImpl.class);
528    
529            private static PortletDataHandlerBoolean _structures =
530                    new PortletDataHandlerBoolean(_NAMESPACE, "structures", true, true);
531    
532            private static PortletDataHandlerBoolean _templates =
533                    new PortletDataHandlerBoolean(_NAMESPACE, "templates");
534    
535    }