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 =
199                            ddmStructurePersistence.findByG_S(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            public List<DDMStructure> getStructureEntries() throws SystemException {
277                    return ddmStructurePersistence.findAll();
278            }
279    
280            public List<DDMStructure> getStructureEntries(long groupId)
281                    throws SystemException {
282    
283                    return ddmStructurePersistence.findByGroupId(groupId);
284            }
285    
286            public List<DDMStructure> getStructureEntries(
287                            long groupId, int start, int end)
288                    throws SystemException {
289    
290                    return ddmStructurePersistence.findByGroupId(groupId, start, end);
291            }
292    
293            public int getStructureEntriesCount(long groupId) throws SystemException {
294                    return ddmStructurePersistence.countByGroupId(groupId);
295            }
296    
297            public List<DDMStructure> search(
298                            long companyId, long[] groupIds, long[] classNameIds,
299                            String keywords, int start, int end,
300                            OrderByComparator orderByComparator)
301                    throws SystemException {
302    
303                    return ddmStructureFinder.findByKeywords(
304                            companyId, groupIds, classNameIds, keywords, start, end,
305                            orderByComparator);
306            }
307    
308            public List<DDMStructure> search(
309                            long companyId, long[] groupIds, long[] classNameIds, String name,
310                            String description, String storageType, int type,
311                            boolean andOperator, int start, int end,
312                            OrderByComparator orderByComparator)
313                    throws SystemException {
314    
315                    return ddmStructureFinder.findByC_G_C_N_D_S_T(
316                            companyId, groupIds, classNameIds, name, description, storageType,
317                            type, andOperator, start, end, orderByComparator);
318            }
319    
320            public int searchCount(
321                            long companyId, long[] groupIds, long[] classNameIds,
322                            String keywords)
323                    throws SystemException {
324    
325                    return ddmStructureFinder.countByKeywords(
326                            companyId, groupIds, classNameIds, keywords);
327            }
328    
329            public int searchCount(
330                            long companyId, long[] groupIds, long[] classNameIds, String name,
331                            String description, String storageType, int type,
332                            boolean andOperator)
333                    throws SystemException {
334    
335                    return ddmStructureFinder.countByC_G_C_N_D_S_T(
336                            companyId, groupIds, classNameIds, name, description, storageType,
337                            type, andOperator);
338            }
339    
340            public DDMStructure updateStructure(
341                            long structureId, Map<Locale, String> nameMap,
342                            Map<Locale, String> descriptionMap, String xsd,
343                            ServiceContext serviceContext)
344                    throws PortalException, SystemException {
345    
346                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
347                            structureId);
348    
349                    return doUpdateStructure(
350                            nameMap, descriptionMap, xsd, serviceContext, structure);
351            }
352    
353            public DDMStructure updateStructure(
354                            long groupId, String structureKey, Map<Locale, String> nameMap,
355                            Map<Locale, String> descriptionMap, String xsd,
356                            ServiceContext serviceContext)
357                    throws PortalException, SystemException {
358    
359                    DDMStructure structure = ddmStructurePersistence.findByG_S(
360                            groupId, structureKey);
361    
362                    return doUpdateStructure(
363                            nameMap, descriptionMap, xsd, serviceContext, structure);
364            }
365    
366            protected void appendNewStructureRequiredFields(
367                    DDMStructure structure, Document templateDocument) {
368    
369                    String xsd = structure.getXsd();
370    
371                    Document structureDocument = null;
372    
373                    try {
374                            structureDocument = SAXReaderUtil.read(xsd);
375                    }
376                    catch (DocumentException de) {
377                            if (_log.isWarnEnabled()) {
378                                    _log.warn(de, de);
379                            }
380    
381                            return;
382                    }
383    
384                    Element templateElement = templateDocument.getRootElement();
385    
386                    XPath structureXPath = SAXReaderUtil.createXPath(
387                            "//dynamic-element[.//meta-data/entry[@name=\"required\"]=" +
388                                    "\"true\"]");
389    
390                    List<Node> nodes = structureXPath.selectNodes(structureDocument);
391    
392                    Iterator<Node> itr = nodes.iterator();
393    
394                    while (itr.hasNext()) {
395                            Element element = (Element)itr.next();
396    
397                            String name = element.attributeValue("name");
398    
399                            XPath templateXPath = SAXReaderUtil.createXPath(
400                                    "//dynamic-element[@name=\"" + name + "\"]");
401    
402                            if (!templateXPath.booleanValueOf(templateDocument)) {
403                                    templateElement.add(element.createCopy());
404                            }
405                    }
406            }
407    
408            protected DDMStructure doUpdateStructure(
409                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
410                            String xsd, ServiceContext serviceContext, DDMStructure structure)
411                    throws PortalException, SystemException {
412    
413                    try {
414                            xsd = DDMXMLUtil.formatXML(xsd);
415                    }
416                    catch (Exception e) {
417                            throw new StructureXsdException();
418                    }
419    
420                    validate(nameMap, xsd);
421    
422                    structure.setModifiedDate(serviceContext.getModifiedDate(null));
423                    structure.setNameMap(nameMap);
424                    structure.setDescriptionMap(descriptionMap);
425                    structure.setXsd(xsd);
426    
427                    ddmStructurePersistence.update(structure, false);
428    
429                    syncStructureTemplatesFields(structure);
430    
431                    return structure;
432            }
433    
434            protected void syncStructureTemplatesFields(DDMStructure structure)
435                    throws PortalException, SystemException {
436    
437                    List<DDMTemplate> templates = ddmTemplateLocalService.getTemplates(
438                            structure.getStructureId(),
439                            DDMTemplateConstants.TEMPLATE_TYPE_DETAIL);
440    
441                    for (DDMTemplate template : templates) {
442                            String script = template.getScript();
443    
444                            Document templateDocument = null;
445    
446                            try {
447                                    templateDocument = SAXReaderUtil.read(script);
448                            }
449                            catch (DocumentException de) {
450                                    if (_log.isWarnEnabled()) {
451                                            _log.warn(de, de);
452                                    }
453    
454                                    continue;
455                            }
456    
457                            Element templateRootElement = templateDocument.getRootElement();
458    
459                            syncStructureTemplatesFields(template, templateRootElement);
460    
461                            appendNewStructureRequiredFields(structure, templateDocument);
462    
463                            try {
464                                    script = DDMXMLUtil.formatXML(templateDocument.asXML());
465                            }
466                            catch (Exception e) {
467                                    throw new StructureXsdException();
468                            }
469    
470                            template.setScript(script);
471    
472                            ddmTemplatePersistence.update(template, false);
473                    }
474            }
475    
476            protected void syncStructureTemplatesFields(
477                            DDMTemplate template, Element templateElement)
478                    throws PortalException, SystemException {
479    
480                    DDMStructure structure = template.getStructure();
481    
482                    List<Element> dynamicElementElements = templateElement.elements(
483                            "dynamic-element");
484    
485                    for (Element dynamicElementElement : dynamicElementElements) {
486                            String dataType = dynamicElementElement.attributeValue("dataType");
487                            String fieldName = dynamicElementElement.attributeValue("name");
488    
489                            if (Validator.isNull(dataType)) {
490                                    continue;
491                            }
492    
493                            if (!structure.hasField(fieldName)) {
494                                    templateElement.remove(dynamicElementElement);
495    
496                                    continue;
497                            }
498    
499                            String mode = template.getMode();
500    
501                            if (mode.equals(DDMTemplateConstants.TEMPLATE_MODE_CREATE)) {
502                                    boolean fieldRequired = structure.getFieldRequired(fieldName);
503    
504                                    List<Element> metadataElements = dynamicElementElement.elements(
505                                            "meta-data");
506    
507                                    for (Element metadataElement : metadataElements) {
508                                            for (Element metadataEntryElement :
509                                                            metadataElement.elements()) {
510    
511                                                    String attributeName =
512                                                            metadataEntryElement.attributeValue("name");
513    
514                                                    if (fieldRequired && attributeName.equals("required")) {
515                                                            metadataEntryElement.setText("true");
516                                                    }
517                                            }
518                                    }
519                            }
520    
521                            syncStructureTemplatesFields(template, dynamicElementElement);
522                    }
523            }
524    
525            protected void validate(List<Element> elements, Set<String> names)
526                    throws PortalException {
527    
528                    for (Element element : elements) {
529                            String elementName = element.getName();
530    
531                            if (elementName.equals("meta-data")) {
532                                    continue;
533                            }
534    
535                            String name = element.attributeValue("name", StringPool.BLANK);
536                            String type = element.attributeValue("type", StringPool.BLANK);
537    
538                            if (Validator.isNull(name) ||
539                                    name.startsWith(DDMStructureConstants.XSD_NAME_RESERVED)) {
540    
541                                    throw new StructureXsdException();
542                            }
543    
544                            char[] charArray = name.toCharArray();
545    
546                            for (int i = 0; i < charArray.length; i++) {
547                                    if (!Character.isLetterOrDigit(charArray[i]) &&
548                                            (charArray[i] != CharPool.DASH) &&
549                                            (charArray[i] != CharPool.UNDERLINE)) {
550    
551                                            throw new StructureXsdException();
552                                    }
553                            }
554    
555                            String path = name;
556    
557                            Element parentElement = element.getParent();
558    
559                            while (!parentElement.isRootElement()) {
560                                    path =
561                                            parentElement.attributeValue("name", StringPool.BLANK) +
562                                                    StringPool.SLASH + path;
563    
564                                    parentElement = parentElement.getParent();
565                            }
566    
567                            path = path.toLowerCase();
568    
569                            if (names.contains(path)) {
570                                    throw new StructureDuplicateElementException();
571                            }
572                            else {
573                                    names.add(path);
574                            }
575    
576                            if (Validator.isNull(type)) {
577                                    throw new StructureXsdException();
578                            }
579    
580                            validate(element.elements(), names);
581                    }
582            }
583    
584            protected void validate(
585                            long groupId, String structureKey, Map<Locale, String> nameMap,
586                            String xsd)
587                    throws PortalException, SystemException {
588    
589                    DDMStructure structure = ddmStructurePersistence.fetchByG_S(
590                            groupId, structureKey);
591    
592                    if (structure != null) {
593                            throw new StructureDuplicateStructureKeyException();
594                    }
595    
596                    validate(nameMap, xsd);
597            }
598    
599            protected void validate(Map<Locale, String> nameMap, String xsd)
600                    throws PortalException {
601    
602                    validateName(nameMap);
603    
604                    if (Validator.isNull(xsd)) {
605                            throw new StructureXsdException();
606                    }
607                    else {
608                            try {
609                                    List<Element> elements = new ArrayList<Element>();
610    
611                                    Document document = SAXReaderUtil.read(xsd);
612    
613                                    Element rootElement = document.getRootElement();
614    
615                                    if (rootElement.elements().isEmpty()) {
616                                            throw new StructureXsdException();
617                                    }
618    
619                                    elements.addAll(rootElement.elements());
620    
621                                    Set<String> elNames = new HashSet<String>();
622    
623                                    validate(elements, elNames);
624                            }
625                            catch (StructureDuplicateElementException fdsee) {
626                                    throw fdsee;
627                            }
628                            catch (StructureXsdException sxe) {
629                                    throw sxe;
630                            }
631                            catch (Exception e) {
632                                    throw new StructureXsdException();
633                            }
634                    }
635            }
636    
637            protected void validateName(Map<Locale, String> nameMap)
638                    throws PortalException {
639    
640                    String name = nameMap.get(LocaleUtil.getDefault());
641    
642                    if (Validator.isNull(name)) {
643                            throw new StructureNameException();
644                    }
645            }
646    
647            private static Log _log = LogFactoryUtil.getLog(
648                    DDMStructureLocalServiceImpl.class);
649    
650    }