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.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryUtil;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.util.CharPool;
023    import com.liferay.portal.kernel.util.LocaleUtil;
024    import com.liferay.portal.kernel.util.OrderByComparator;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.Validator;
027    import com.liferay.portal.kernel.xml.Document;
028    import com.liferay.portal.kernel.xml.DocumentException;
029    import com.liferay.portal.kernel.xml.Element;
030    import com.liferay.portal.kernel.xml.Node;
031    import com.liferay.portal.kernel.xml.SAXReaderUtil;
032    import com.liferay.portal.kernel.xml.XPath;
033    import com.liferay.portal.model.ResourceConstants;
034    import com.liferay.portal.model.User;
035    import com.liferay.portal.service.ServiceContext;
036    import com.liferay.portlet.dynamicdatamapping.RequiredStructureException;
037    import com.liferay.portlet.dynamicdatamapping.StructureDuplicateElementException;
038    import com.liferay.portlet.dynamicdatamapping.StructureDuplicateStructureKeyException;
039    import com.liferay.portlet.dynamicdatamapping.StructureNameException;
040    import com.liferay.portlet.dynamicdatamapping.StructureXsdException;
041    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
042    import com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants;
043    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
044    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplateConstants;
045    import com.liferay.portlet.dynamicdatamapping.service.base.DDMStructureLocalServiceBaseImpl;
046    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
047    
048    import java.util.ArrayList;
049    import java.util.Date;
050    import java.util.HashSet;
051    import java.util.Iterator;
052    import java.util.List;
053    import java.util.Locale;
054    import java.util.Map;
055    import java.util.Set;
056    
057    /**
058     * @author Brian Wing Shun Chan
059     * @author Bruno Basto
060     * @author Marcellus Tavares
061     */
062    public class DDMStructureLocalServiceImpl
063            extends DDMStructureLocalServiceBaseImpl {
064    
065            public DDMStructure addStructure(
066                            long userId, long groupId, long classNameId, String structureKey,
067                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
068                            String xsd, String storageType, int type,
069                            ServiceContext serviceContext)
070                    throws PortalException, SystemException {
071    
072                    // Structure
073    
074                    User user = userPersistence.findByPrimaryKey(userId);
075    
076                    if (Validator.isNull(structureKey)) {
077                            structureKey = String.valueOf(counterLocalService.increment());
078                    }
079    
080                    try {
081                            xsd = DDMXMLUtil.formatXML(xsd);
082                    }
083                    catch (Exception e) {
084                            throw new StructureXsdException();
085                    }
086    
087                    Date now = new Date();
088    
089                    validate(groupId, structureKey, nameMap, xsd);
090    
091                    long structureId = counterLocalService.increment();
092    
093                    DDMStructure structure = ddmStructurePersistence.create(structureId);
094    
095                    structure.setUuid(serviceContext.getUuid());
096                    structure.setGroupId(serviceContext.getScopeGroupId());
097                    structure.setCompanyId(user.getCompanyId());
098                    structure.setUserId(user.getUserId());
099                    structure.setUserName(user.getFullName());
100                    structure.setCreateDate(serviceContext.getCreateDate(now));
101                    structure.setModifiedDate(serviceContext.getModifiedDate(now));
102                    structure.setClassNameId(classNameId);
103                    structure.setStructureKey(structureKey);
104                    structure.setNameMap(nameMap);
105                    structure.setDescriptionMap(descriptionMap);
106                    structure.setXsd(xsd);
107                    structure.setStorageType(storageType);
108                    structure.setType(type);
109    
110                    ddmStructurePersistence.update(structure, false);
111    
112                    // Resources
113    
114                    if (serviceContext.isAddGroupPermissions() ||
115                            serviceContext.isAddGuestPermissions()) {
116    
117                            addStructureResources(
118                                    structure, serviceContext.isAddGroupPermissions(),
119                                    serviceContext.isAddGuestPermissions());
120                    }
121                    else {
122                            addStructureResources(
123                                    structure, serviceContext.getGroupPermissions(),
124                                    serviceContext.getGuestPermissions());
125                    }
126    
127                    return structure;
128            }
129    
130            public void addStructureResources(
131                            DDMStructure structure, boolean addGroupPermissions,
132                            boolean addGuestPermissions)
133                    throws PortalException, SystemException {
134    
135                    resourceLocalService.addResources(
136                            structure.getCompanyId(), structure.getGroupId(),
137                            structure.getUserId(), DDMStructure.class.getName(),
138                            structure.getStructureId(), false, addGroupPermissions,
139                            addGuestPermissions);
140            }
141    
142            public void addStructureResources(
143                            DDMStructure structure, String[] groupPermissions,
144                            String[] guestPermissions)
145                    throws PortalException, SystemException {
146    
147                    resourceLocalService.addModelResources(
148                            structure.getCompanyId(), structure.getGroupId(),
149                            structure.getUserId(), DDMStructure.class.getName(),
150                            structure.getStructureId(), groupPermissions, guestPermissions);
151            }
152    
153            public DDMStructure copyStructure(
154                            long userId, long structureId, Map<Locale, String> nameMap,
155                            Map<Locale, String> descriptionMap, ServiceContext serviceContext)
156                    throws PortalException, SystemException {
157    
158                    DDMStructure structure = getStructure(structureId);
159    
160                    return addStructure(
161                            userId, structure.getGroupId(), structure.getClassNameId(), null,
162                            nameMap, descriptionMap, structure.getXsd(),
163                            structure.getStorageType(), structure.getType(), serviceContext);
164            }
165    
166            public void deleteStructure(DDMStructure structure)
167                    throws PortalException, SystemException {
168    
169                    if (ddmStructureLinkPersistence.countByStructureId(
170                                    structure.getStructureId()) > 0) {
171    
172                            throw new RequiredStructureException();
173                    }
174    
175                    // Structure
176    
177                    ddmStructurePersistence.remove(structure);
178    
179                    // Resources
180    
181                    resourceLocalService.deleteResource(
182                            structure.getCompanyId(), DDMStructure.class.getName(),
183                            ResourceConstants.SCOPE_INDIVIDUAL, structure.getStructureId());
184            }
185    
186            public void deleteStructure(long structureId)
187                    throws PortalException, SystemException {
188    
189                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
190                            structureId);
191    
192                    deleteStructure(structure);
193            }
194    
195            public void deleteStructure(long groupId, String structureKey)
196                    throws PortalException, SystemException {
197    
198                    DDMStructure structure = ddmStructurePersistence.findByG_S(
199                            groupId, structureKey);
200    
201                    deleteStructure(structure);
202            }
203    
204            public void deleteStructures(long groupId)
205                    throws PortalException, SystemException {
206    
207                    List<DDMStructure> structures = ddmStructurePersistence.findByGroupId(
208                            groupId);
209    
210                    for (DDMStructure structure : structures) {
211                            deleteStructure(structure);
212                    }
213            }
214    
215            public DDMStructure fetchStructure(long structureId)
216                    throws SystemException {
217    
218                    return ddmStructurePersistence.fetchByPrimaryKey(structureId);
219            }
220    
221            public DDMStructure fetchStructure(long groupId, String structureKey)
222                    throws SystemException {
223    
224                    return ddmStructurePersistence.fetchByG_S(groupId, structureKey);
225            }
226    
227            public List<DDMStructure> getClassStructures(long classNameId)
228                    throws SystemException {
229    
230                    return ddmStructurePersistence.findByClassNameId(classNameId);
231            }
232    
233            public List<DDMStructure> getClassStructures(
234                            long classNameId, int start, int end)
235                    throws SystemException {
236    
237                    return ddmStructurePersistence.findByClassNameId(
238                            classNameId, start, end);
239            }
240    
241            public List<DDMStructure> getClassStructures(
242                            long classNameId, OrderByComparator orderByComparator)
243                    throws SystemException {
244    
245                    return ddmStructurePersistence.findByClassNameId(
246                            classNameId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
247                            orderByComparator);
248            }
249    
250            public List<DDMStructure> getDLFileEntryTypeStructures(
251                            long dlFileEntryTypeId)
252                    throws SystemException {
253    
254                    return dlFileEntryTypePersistence.getDDMStructures(dlFileEntryTypeId);
255            }
256    
257            public DDMStructure getStructure(long structureId)
258                    throws PortalException, SystemException {
259    
260                    return ddmStructurePersistence.findByPrimaryKey(structureId);
261            }
262    
263            public DDMStructure getStructure(long groupId, String structureKey)
264                    throws PortalException, SystemException {
265    
266                    return ddmStructurePersistence.findByG_S(groupId, structureKey);
267            }
268    
269            public List<DDMStructure> getStructure(
270                            long groupId, String name, String description)
271                    throws SystemException {
272    
273                    return ddmStructurePersistence.findByG_N_D(groupId, name, description);
274            }
275    
276            /**
277             * @deprecated {@link #getStructures}
278             */
279            public List<DDMStructure> getStructureEntries() throws SystemException {
280                    return getStructures();
281            }
282    
283            /**
284             * @deprecated {@link #getStructures(long)}
285             */
286            public List<DDMStructure> getStructureEntries(long groupId)
287                    throws SystemException {
288    
289                    return getStructures(groupId);
290            }
291    
292            /**
293             * @deprecated {@link #getStructures(long, int, int)}
294             */
295            public List<DDMStructure> getStructureEntries(
296                            long groupId, int start, int end)
297                    throws SystemException {
298    
299                    return getStructures(groupId, start, end);
300            }
301    
302            public List<DDMStructure> getStructures() throws SystemException {
303                    return ddmStructurePersistence.findAll();
304            }
305    
306            public List<DDMStructure> getStructures(long groupId)
307                    throws SystemException {
308    
309                    return ddmStructurePersistence.findByGroupId(groupId);
310            }
311    
312            public List<DDMStructure> getStructures(long groupId, int start, int end)
313                    throws SystemException {
314    
315                    return ddmStructurePersistence.findByGroupId(groupId, start, end);
316            }
317    
318            public int getStructuresCount(long groupId) throws SystemException {
319                    return ddmStructurePersistence.countByGroupId(groupId);
320            }
321    
322            public List<DDMStructure> search(
323                            long companyId, long[] groupIds, long[] classNameIds,
324                            String keywords, int start, int end,
325                            OrderByComparator orderByComparator)
326                    throws SystemException {
327    
328                    return ddmStructureFinder.findByKeywords(
329                            companyId, groupIds, classNameIds, keywords, start, end,
330                            orderByComparator);
331            }
332    
333            public List<DDMStructure> search(
334                            long companyId, long[] groupIds, long[] classNameIds, String name,
335                            String description, String storageType, int type,
336                            boolean andOperator, int start, int end,
337                            OrderByComparator orderByComparator)
338                    throws SystemException {
339    
340                    return ddmStructureFinder.findByC_G_C_N_D_S_T(
341                            companyId, groupIds, classNameIds, name, description, storageType,
342                            type, andOperator, start, end, orderByComparator);
343            }
344    
345            public int searchCount(
346                            long companyId, long[] groupIds, long[] classNameIds,
347                            String keywords)
348                    throws SystemException {
349    
350                    return ddmStructureFinder.countByKeywords(
351                            companyId, groupIds, classNameIds, keywords);
352            }
353    
354            public int searchCount(
355                            long companyId, long[] groupIds, long[] classNameIds, String name,
356                            String description, String storageType, int type,
357                            boolean andOperator)
358                    throws SystemException {
359    
360                    return ddmStructureFinder.countByC_G_C_N_D_S_T(
361                            companyId, groupIds, classNameIds, name, description, storageType,
362                            type, andOperator);
363            }
364    
365            public DDMStructure updateStructure(
366                            long structureId, Map<Locale, String> nameMap,
367                            Map<Locale, String> descriptionMap, String xsd,
368                            ServiceContext serviceContext)
369                    throws PortalException, SystemException {
370    
371                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
372                            structureId);
373    
374                    return doUpdateStructure(
375                            nameMap, descriptionMap, xsd, serviceContext, structure);
376            }
377    
378            public DDMStructure updateStructure(
379                            long groupId, String structureKey, Map<Locale, String> nameMap,
380                            Map<Locale, String> descriptionMap, String xsd,
381                            ServiceContext serviceContext)
382                    throws PortalException, SystemException {
383    
384                    DDMStructure structure = ddmStructurePersistence.findByG_S(
385                            groupId, structureKey);
386    
387                    return doUpdateStructure(
388                            nameMap, descriptionMap, xsd, serviceContext, structure);
389            }
390    
391            protected void appendNewStructureRequiredFields(
392                    DDMStructure structure, Document templateDocument) {
393    
394                    String xsd = structure.getXsd();
395    
396                    Document structureDocument = null;
397    
398                    try {
399                            structureDocument = SAXReaderUtil.read(xsd);
400                    }
401                    catch (DocumentException de) {
402                            if (_log.isWarnEnabled()) {
403                                    _log.warn(de, de);
404                            }
405    
406                            return;
407                    }
408    
409                    Element templateElement = templateDocument.getRootElement();
410    
411                    XPath structureXPath = SAXReaderUtil.createXPath(
412                            "//dynamic-element[.//meta-data/entry[@name=\"required\"]=" +
413                                    "\"true\"]");
414    
415                    List<Node> nodes = structureXPath.selectNodes(structureDocument);
416    
417                    Iterator<Node> itr = nodes.iterator();
418    
419                    while (itr.hasNext()) {
420                            Element element = (Element)itr.next();
421    
422                            String name = element.attributeValue("name");
423    
424                            XPath templateXPath = SAXReaderUtil.createXPath(
425                                    "//dynamic-element[@name=\"" + name + "\"]");
426    
427                            if (!templateXPath.booleanValueOf(templateDocument)) {
428                                    templateElement.add(element.createCopy());
429                            }
430                    }
431            }
432    
433            protected DDMStructure doUpdateStructure(
434                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
435                            String xsd, ServiceContext serviceContext, DDMStructure structure)
436                    throws PortalException, SystemException {
437    
438                    try {
439                            xsd = DDMXMLUtil.formatXML(xsd);
440                    }
441                    catch (Exception e) {
442                            throw new StructureXsdException();
443                    }
444    
445                    validate(nameMap, xsd);
446    
447                    structure.setModifiedDate(serviceContext.getModifiedDate(null));
448                    structure.setNameMap(nameMap);
449                    structure.setDescriptionMap(descriptionMap);
450                    structure.setXsd(xsd);
451    
452                    ddmStructurePersistence.update(structure, false);
453    
454                    syncStructureTemplatesFields(structure);
455    
456                    return structure;
457            }
458    
459            protected void syncStructureTemplatesFields(DDMStructure structure)
460                    throws PortalException, SystemException {
461    
462                    List<DDMTemplate> templates = ddmTemplateLocalService.getTemplates(
463                            structure.getStructureId(),
464                            DDMTemplateConstants.TEMPLATE_TYPE_DETAIL);
465    
466                    for (DDMTemplate template : templates) {
467                            String script = template.getScript();
468    
469                            Document templateDocument = null;
470    
471                            try {
472                                    templateDocument = SAXReaderUtil.read(script);
473                            }
474                            catch (DocumentException de) {
475                                    if (_log.isWarnEnabled()) {
476                                            _log.warn(de, de);
477                                    }
478    
479                                    continue;
480                            }
481    
482                            Element templateRootElement = templateDocument.getRootElement();
483    
484                            syncStructureTemplatesFields(template, templateRootElement);
485    
486                            appendNewStructureRequiredFields(structure, templateDocument);
487    
488                            try {
489                                    script = DDMXMLUtil.formatXML(templateDocument.asXML());
490                            }
491                            catch (Exception e) {
492                                    throw new StructureXsdException();
493                            }
494    
495                            template.setScript(script);
496    
497                            ddmTemplatePersistence.update(template, false);
498                    }
499            }
500    
501            protected void syncStructureTemplatesFields(
502                            DDMTemplate template, Element templateElement)
503                    throws PortalException, SystemException {
504    
505                    DDMStructure structure = template.getStructure();
506    
507                    List<Element> dynamicElementElements = templateElement.elements(
508                            "dynamic-element");
509    
510                    for (Element dynamicElementElement : dynamicElementElements) {
511                            String dataType = dynamicElementElement.attributeValue("dataType");
512                            String fieldName = dynamicElementElement.attributeValue("name");
513    
514                            if (Validator.isNull(dataType)) {
515                                    continue;
516                            }
517    
518                            if (!structure.hasField(fieldName)) {
519                                    templateElement.remove(dynamicElementElement);
520    
521                                    continue;
522                            }
523    
524                            String mode = template.getMode();
525    
526                            if (mode.equals(DDMTemplateConstants.TEMPLATE_MODE_CREATE)) {
527                                    boolean fieldRequired = structure.getFieldRequired(fieldName);
528    
529                                    List<Element> metadataElements = dynamicElementElement.elements(
530                                            "meta-data");
531    
532                                    for (Element metadataElement : metadataElements) {
533                                            for (Element metadataEntryElement :
534                                                            metadataElement.elements()) {
535    
536                                                    String attributeName =
537                                                            metadataEntryElement.attributeValue("name");
538    
539                                                    if (fieldRequired && attributeName.equals("required")) {
540                                                            metadataEntryElement.setText("true");
541                                                    }
542                                            }
543                                    }
544                            }
545    
546                            syncStructureTemplatesFields(template, dynamicElementElement);
547                    }
548            }
549    
550            protected void validate(List<Element> elements, Set<String> names)
551                    throws PortalException {
552    
553                    for (Element element : elements) {
554                            String elementName = element.getName();
555    
556                            if (elementName.equals("meta-data")) {
557                                    continue;
558                            }
559    
560                            String name = element.attributeValue("name", StringPool.BLANK);
561                            String type = element.attributeValue("type", StringPool.BLANK);
562    
563                            if (Validator.isNull(name) ||
564                                    name.startsWith(DDMStructureConstants.XSD_NAME_RESERVED)) {
565    
566                                    throw new StructureXsdException();
567                            }
568    
569                            char[] charArray = name.toCharArray();
570    
571                            for (int i = 0; i < charArray.length; i++) {
572                                    if (!Character.isLetterOrDigit(charArray[i]) &&
573                                            (charArray[i] != CharPool.DASH) &&
574                                            (charArray[i] != CharPool.UNDERLINE)) {
575    
576                                            throw new StructureXsdException();
577                                    }
578                            }
579    
580                            String path = name;
581    
582                            Element parentElement = element.getParent();
583    
584                            while (!parentElement.isRootElement()) {
585                                    path =
586                                            parentElement.attributeValue("name", StringPool.BLANK) +
587                                                    StringPool.SLASH + path;
588    
589                                    parentElement = parentElement.getParent();
590                            }
591    
592                            path = path.toLowerCase();
593    
594                            if (names.contains(path)) {
595                                    throw new StructureDuplicateElementException();
596                            }
597                            else {
598                                    names.add(path);
599                            }
600    
601                            if (Validator.isNull(type)) {
602                                    throw new StructureXsdException();
603                            }
604    
605                            validate(element.elements(), names);
606                    }
607            }
608    
609            protected void validate(
610                            long groupId, String structureKey, Map<Locale, String> nameMap,
611                            String xsd)
612                    throws PortalException, SystemException {
613    
614                    DDMStructure structure = ddmStructurePersistence.fetchByG_S(
615                            groupId, structureKey);
616    
617                    if (structure != null) {
618                            throw new StructureDuplicateStructureKeyException();
619                    }
620    
621                    validate(nameMap, xsd);
622            }
623    
624            protected void validate(Map<Locale, String> nameMap, String xsd)
625                    throws PortalException {
626    
627                    validateName(nameMap);
628    
629                    if (Validator.isNull(xsd)) {
630                            throw new StructureXsdException();
631                    }
632                    else {
633                            try {
634                                    List<Element> elements = new ArrayList<Element>();
635    
636                                    Document document = SAXReaderUtil.read(xsd);
637    
638                                    Element rootElement = document.getRootElement();
639    
640                                    if (rootElement.elements().isEmpty()) {
641                                            throw new StructureXsdException();
642                                    }
643    
644                                    elements.addAll(rootElement.elements());
645    
646                                    Set<String> elNames = new HashSet<String>();
647    
648                                    validate(elements, elNames);
649                            }
650                            catch (StructureDuplicateElementException fdsee) {
651                                    throw fdsee;
652                            }
653                            catch (StructureXsdException sxe) {
654                                    throw sxe;
655                            }
656                            catch (Exception e) {
657                                    throw new StructureXsdException();
658                            }
659                    }
660            }
661    
662            protected void validateName(Map<Locale, String> nameMap)
663                    throws PortalException {
664    
665                    String name = nameMap.get(LocaleUtil.getDefault());
666    
667                    if (Validator.isNull(name)) {
668                            throw new StructureNameException();
669                    }
670            }
671    
672            private static Log _log = LogFactoryUtil.getLog(
673                    DDMStructureLocalServiceImpl.class);
674    
675    }