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