001    /**
002     * Copyright (c) 2000-2013 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.journal.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.StringUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.kernel.xml.Document;
029    import com.liferay.portal.kernel.xml.Element;
030    import com.liferay.portal.kernel.xml.SAXReaderUtil;
031    import com.liferay.portal.model.Group;
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.portal.util.PortalUtil;
036    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
037    import com.liferay.portlet.journal.DuplicateStructureElementException;
038    import com.liferay.portlet.journal.DuplicateStructureIdException;
039    import com.liferay.portlet.journal.NoSuchArticleException;
040    import com.liferay.portlet.journal.NoSuchStructureException;
041    import com.liferay.portlet.journal.RequiredStructureException;
042    import com.liferay.portlet.journal.StructureIdException;
043    import com.liferay.portlet.journal.StructureInheritanceException;
044    import com.liferay.portlet.journal.StructureNameException;
045    import com.liferay.portlet.journal.StructureXsdException;
046    import com.liferay.portlet.journal.model.JournalArticle;
047    import com.liferay.portlet.journal.model.JournalArticleConstants;
048    import com.liferay.portlet.journal.model.JournalStructure;
049    import com.liferay.portlet.journal.model.JournalStructureConstants;
050    import com.liferay.portlet.journal.service.base.JournalStructureLocalServiceBaseImpl;
051    import com.liferay.portlet.journal.util.JournalUtil;
052    import com.liferay.portlet.journal.util.comparator.StructurePKComparator;
053    
054    import java.util.ArrayList;
055    import java.util.Date;
056    import java.util.HashSet;
057    import java.util.List;
058    import java.util.Locale;
059    import java.util.Map;
060    import java.util.Set;
061    
062    /**
063     * @author Brian Wing Shun Chan
064     * @author Raymond Augé
065     */
066    public class JournalStructureLocalServiceImpl
067            extends JournalStructureLocalServiceBaseImpl {
068    
069            public JournalStructure addStructure(
070                            long userId, long groupId, String structureId,
071                            boolean autoStructureId, String parentStructureId,
072                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
073                            String xsd, ServiceContext serviceContext)
074                    throws PortalException, SystemException {
075    
076                    // Structure
077    
078                    User user = userPersistence.findByPrimaryKey(userId);
079                    structureId = structureId.trim().toUpperCase();
080                    Date now = new Date();
081    
082                    try {
083                            xsd = JournalUtil.validateXSD(xsd);
084                            xsd = DDMXMLUtil.formatXML(xsd);
085                    }
086                    catch (Exception e) {
087                            throw new StructureXsdException();
088                    }
089    
090                    if (autoStructureId) {
091                            structureId = String.valueOf(counterLocalService.increment());
092                    }
093    
094                    validate(
095                            groupId, structureId, autoStructureId, parentStructureId, nameMap,
096                            xsd);
097    
098                    long id = counterLocalService.increment();
099    
100                    JournalStructure structure = journalStructurePersistence.create(id);
101    
102                    structure.setUuid(serviceContext.getUuid());
103                    structure.setGroupId(groupId);
104                    structure.setCompanyId(user.getCompanyId());
105                    structure.setUserId(user.getUserId());
106                    structure.setUserName(user.getFullName());
107                    structure.setCreateDate(serviceContext.getCreateDate(now));
108                    structure.setModifiedDate(serviceContext.getModifiedDate(now));
109                    structure.setStructureId(structureId);
110                    structure.setParentStructureId(parentStructureId);
111                    structure.setNameMap(nameMap);
112                    structure.setDescriptionMap(descriptionMap);
113                    structure.setXsd(xsd);
114                    structure.setExpandoBridgeAttributes(serviceContext);
115    
116                    journalStructurePersistence.update(structure);
117    
118                    // Resources
119    
120                    if (serviceContext.isAddGroupPermissions() ||
121                            serviceContext.isAddGuestPermissions()) {
122    
123                            addStructureResources(
124                                    structure, serviceContext.isAddGroupPermissions(),
125                                    serviceContext.isAddGuestPermissions());
126                    }
127                    else {
128                            addStructureResources(
129                                    structure, serviceContext.getGroupPermissions(),
130                                    serviceContext.getGuestPermissions());
131                    }
132    
133                    return structure;
134            }
135    
136            public void addStructureResources(
137                            JournalStructure structure, boolean addGroupPermissions,
138                            boolean addGuestPermissions)
139                    throws PortalException, SystemException {
140    
141                    resourceLocalService.addResources(
142                            structure.getCompanyId(), structure.getGroupId(),
143                            structure.getUserId(), JournalStructure.class.getName(),
144                            structure.getId(), false, addGroupPermissions, addGuestPermissions);
145            }
146    
147            public void addStructureResources(
148                            JournalStructure structure, String[] groupPermissions,
149                            String[] guestPermissions)
150                    throws PortalException, SystemException {
151    
152                    resourceLocalService.addModelResources(
153                            structure.getCompanyId(), structure.getGroupId(),
154                            structure.getUserId(), JournalStructure.class.getName(),
155                            structure.getId(), groupPermissions, guestPermissions);
156            }
157    
158            public void addStructureResources(
159                            long groupId, String structureId, boolean addGroupPermissions,
160                            boolean addGuestPermissions)
161                    throws PortalException, SystemException {
162    
163                    JournalStructure structure = journalStructurePersistence.findByG_S(
164                            groupId, structureId);
165    
166                    addStructureResources(
167                            structure, addGroupPermissions, addGuestPermissions);
168            }
169    
170            public void addStructureResources(
171                            long groupId, String structureId, String[] groupPermissions,
172                            String[] guestPermissions)
173                    throws PortalException, SystemException {
174    
175                    JournalStructure structure = journalStructurePersistence.findByG_S(
176                            groupId, structureId);
177    
178                    addStructureResources(structure, groupPermissions, guestPermissions);
179            }
180    
181            public void checkNewLine(long groupId, String structureId)
182                    throws PortalException, SystemException {
183    
184                    JournalStructure structure = journalStructurePersistence.findByG_S(
185                            groupId, structureId);
186    
187                    String xsd = structure.getXsd();
188    
189                    if ((xsd != null) && xsd.contains("\\n")) {
190                            xsd = StringUtil.replace(
191                                    xsd, new String[] {"\\n", "\\r"}, new String[] {"\n", "\r"});
192    
193                            structure.setXsd(xsd);
194    
195                            journalStructurePersistence.update(structure);
196                    }
197            }
198    
199            public JournalStructure copyStructure(
200                            long userId, long groupId, String oldStructureId,
201                            String newStructureId, boolean autoStructureId)
202                    throws PortalException, SystemException {
203    
204                    // Structure
205    
206                    User user = userPersistence.findByPrimaryKey(userId);
207                    oldStructureId = oldStructureId.trim().toUpperCase();
208                    newStructureId = newStructureId.trim().toUpperCase();
209                    Date now = new Date();
210    
211                    JournalStructure oldStructure = journalStructurePersistence.findByG_S(
212                            groupId, oldStructureId);
213    
214                    if (autoStructureId) {
215                            newStructureId = String.valueOf(counterLocalService.increment());
216                    }
217                    else {
218                            validateStructureId(newStructureId);
219    
220                            JournalStructure newStructure =
221                                    journalStructurePersistence.fetchByG_S(groupId, newStructureId);
222    
223                            if (newStructure != null) {
224                                    throw new DuplicateStructureIdException();
225                            }
226                    }
227    
228                    long id = counterLocalService.increment();
229    
230                    JournalStructure newStructure = journalStructurePersistence.create(id);
231    
232                    newStructure.setGroupId(groupId);
233                    newStructure.setCompanyId(user.getCompanyId());
234                    newStructure.setUserId(user.getUserId());
235                    newStructure.setUserName(user.getFullName());
236                    newStructure.setCreateDate(now);
237                    newStructure.setModifiedDate(now);
238                    newStructure.setStructureId(newStructureId);
239                    newStructure.setNameMap(oldStructure.getNameMap());
240                    newStructure.setDescriptionMap(oldStructure.getDescriptionMap());
241                    newStructure.setXsd(oldStructure.getXsd());
242                    newStructure.setExpandoBridgeAttributes(oldStructure);
243    
244                    journalStructurePersistence.update(newStructure);
245    
246                    // Resources
247    
248                    addStructureResources(newStructure, true, true);
249    
250                    return newStructure;
251            }
252    
253            public void deleteStructure(JournalStructure structure)
254                    throws PortalException, SystemException {
255    
256                    Group companyGroup = groupLocalService.getCompanyGroup(
257                            structure.getCompanyId());
258    
259                    if (structure.getGroupId() == companyGroup.getGroupId()) {
260                            if (journalArticlePersistence.countByStructureId(
261                                            structure.getStructureId()) > 0) {
262    
263                                    throw new RequiredStructureException(
264                                            RequiredStructureException.REFERENCED_WEB_CONTENT);
265                            }
266    
267                            if (journalStructurePersistence.countByParentStructureId(
268                                            structure.getStructureId()) > 0) {
269    
270                                    throw new RequiredStructureException(
271                                            RequiredStructureException.REFERENCED_STRUCTURE);
272                            }
273    
274                            if (journalTemplatePersistence.countByStructureId(
275                                            structure.getStructureId()) > 0) {
276    
277                                    throw new RequiredStructureException(
278                                            RequiredStructureException.REFERENCED_TEMPLATE);
279                            }
280                    }
281                    else {
282                            if (journalArticlePersistence.countByG_C_S(
283                                            structure.getGroupId(),
284                                            JournalArticleConstants.CLASSNAME_ID_DEFAULT,
285                                            structure.getStructureId()) > 0) {
286    
287                                    throw new RequiredStructureException(
288                                            RequiredStructureException.REFERENCED_WEB_CONTENT);
289                            }
290    
291                            if (journalStructurePersistence.countByG_P(
292                                            structure.getGroupId(), structure.getStructureId()) > 0) {
293    
294                                    throw new RequiredStructureException(
295                                            RequiredStructureException.REFERENCED_STRUCTURE);
296                            }
297    
298                            if (journalTemplatePersistence.countByG_S(
299                                            structure.getGroupId(), structure.getStructureId()) > 0) {
300    
301                                    throw new RequiredStructureException(
302                                            RequiredStructureException.REFERENCED_TEMPLATE);
303                            }
304                    }
305    
306                    // WebDAVProps
307    
308                    webDAVPropsLocalService.deleteWebDAVProps(
309                            JournalStructure.class.getName(), structure.getId());
310    
311                    // Expando
312    
313                    expandoValueLocalService.deleteValues(
314                            JournalStructure.class.getName(), structure.getId());
315    
316                    // Resources
317    
318                    resourceLocalService.deleteResource(
319                            structure.getCompanyId(), JournalStructure.class.getName(),
320                            ResourceConstants.SCOPE_INDIVIDUAL, structure.getId());
321    
322                    // Article
323    
324                    try {
325                            long classNameId = PortalUtil.getClassNameId(
326                                    JournalStructure.class.getName());
327    
328                            List<JournalArticle> articles =
329                                    journalArticlePersistence.findByG_C_C(
330                                            structure.getGroupId(), classNameId, structure.getId());
331    
332                            for (JournalArticle article : articles) {
333                                    journalArticleLocalService.deleteArticle(article, null, null);
334                            }
335                    }
336                    catch (NoSuchArticleException nsae) {
337                    }
338    
339                    // Structure
340    
341                    journalStructurePersistence.remove(structure);
342            }
343    
344            public void deleteStructure(long groupId, String structureId)
345                    throws PortalException, SystemException {
346    
347                    structureId = structureId.trim().toUpperCase();
348    
349                    JournalStructure structure = journalStructurePersistence.findByG_S(
350                            groupId, structureId);
351    
352                    deleteStructure(structure);
353            }
354    
355            public void deleteStructures(long groupId)
356                    throws PortalException, SystemException {
357    
358                    List<JournalStructure> structures =
359                            journalStructurePersistence.findByGroupId(
360                                    groupId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
361                                    new StructurePKComparator());
362    
363                    for (JournalStructure structure : structures) {
364                            deleteStructure(structure);
365                    }
366            }
367    
368            public JournalStructure getStructure(long id)
369                    throws PortalException, SystemException {
370    
371                    return journalStructurePersistence.findByPrimaryKey(id);
372            }
373    
374            public JournalStructure getStructure(long groupId, String structureId)
375                    throws PortalException, SystemException {
376    
377                    return getStructure(groupId, structureId, false);
378            }
379    
380            public JournalStructure getStructure(
381                            long groupId, String structureId, boolean includeGlobalStructures)
382                    throws PortalException, SystemException {
383    
384                    structureId = structureId.trim().toUpperCase();
385    
386                    if (groupId == 0) {
387                            _log.error(
388                                    "No group ID was passed for " + structureId + ". Group ID is " +
389                                            "required since 4.2.0. Please update all custom code and " +
390                                                    "data that references structures without a group ID.");
391    
392                            List<JournalStructure> structures =
393                                    journalStructurePersistence.findByStructureId(structureId);
394    
395                            if (!structures.isEmpty()) {
396                                    return structures.get(0);
397                            }
398    
399                            throw new NoSuchStructureException(
400                                    "No JournalStructure exists with the structure ID " +
401                                            structureId);
402                    }
403    
404                    JournalStructure structure = journalStructurePersistence.fetchByG_S(
405                            groupId, structureId);
406    
407                    if (structure != null) {
408                            return structure;
409                    }
410    
411                    if (!includeGlobalStructures) {
412                            throw new NoSuchStructureException(
413                                    "No JournalStructure exists with the structure ID " +
414                                            structureId);
415                    }
416    
417                    Group group = groupPersistence.findByPrimaryKey(groupId);
418    
419                    Group companyGroup = groupLocalService.getCompanyGroup(
420                            group.getCompanyId());
421    
422                    return journalStructurePersistence.findByG_S(
423                            companyGroup.getGroupId(), structureId);
424            }
425    
426            public List<JournalStructure> getStructures() throws SystemException {
427                    return journalStructurePersistence.findAll();
428            }
429    
430            public List<JournalStructure> getStructures(long groupId)
431                    throws SystemException {
432    
433                    return journalStructurePersistence.findByGroupId(groupId);
434            }
435    
436            public List<JournalStructure> getStructures(
437                            long groupId, int start, int end)
438                    throws SystemException {
439    
440                    return journalStructurePersistence.findByGroupId(groupId, start, end);
441            }
442    
443            public int getStructuresCount(long groupId) throws SystemException {
444                    return journalStructurePersistence.countByGroupId(groupId);
445            }
446    
447            public List<JournalStructure> search(
448                            long companyId, long[] groupIds, String keywords, int start,
449                            int end, OrderByComparator obc)
450                    throws SystemException {
451    
452                    return journalStructureFinder.findByKeywords(
453                            companyId, groupIds, keywords, start, end, obc);
454            }
455    
456            public List<JournalStructure> search(
457                            long companyId, long[] groupIds, String structureId, String name,
458                            String description, boolean andOperator, int start, int end,
459                            OrderByComparator obc)
460                    throws SystemException {
461    
462                    return journalStructureFinder.findByC_G_S_N_D(
463                            companyId, groupIds, structureId, name, description, andOperator,
464                            start, end, obc);
465            }
466    
467            public int searchCount(long companyId, long[] groupIds, String keywords)
468                    throws SystemException {
469    
470                    return journalStructureFinder.countByKeywords(
471                            companyId, groupIds, keywords);
472            }
473    
474            public int searchCount(
475                            long companyId, long[] groupIds, String structureId, String name,
476                            String description, boolean andOperator)
477                    throws SystemException {
478    
479                    return journalStructureFinder.countByC_G_S_N_D(
480                            companyId, groupIds, structureId, name, description, andOperator);
481            }
482    
483            public JournalStructure updateStructure(
484                            long groupId, String structureId, String parentStructureId,
485                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
486                            String xsd, ServiceContext serviceContext)
487                    throws PortalException, SystemException {
488    
489                    structureId = structureId.trim().toUpperCase();
490    
491                    try {
492                            xsd = JournalUtil.validateXSD(xsd);
493                            xsd = DDMXMLUtil.formatXML(xsd);
494                    }
495                    catch (Exception e) {
496                            throw new StructureXsdException();
497                    }
498    
499                    validateParentStructureId(groupId, structureId, parentStructureId);
500                    validate(groupId, parentStructureId, nameMap, xsd);
501    
502                    JournalStructure structure = journalStructurePersistence.findByG_S(
503                            groupId, structureId);
504    
505                    structure.setModifiedDate(serviceContext.getModifiedDate(null));
506                    structure.setParentStructureId(parentStructureId);
507                    structure.setNameMap(nameMap);
508                    structure.setDescriptionMap(descriptionMap);
509                    structure.setXsd(xsd);
510                    structure.setExpandoBridgeAttributes(serviceContext);
511    
512                    journalStructurePersistence.update(structure);
513    
514                    return structure;
515            }
516    
517            protected void appendParentStructureElements(
518                            long groupId, String parentStructureId, List<Element> elements)
519                    throws Exception {
520    
521                    if (Validator.isNull(parentStructureId)) {
522                            return;
523                    }
524    
525                    JournalStructure parentStructure = getParentStructure(
526                            groupId, parentStructureId);
527    
528                    appendParentStructureElements(
529                            groupId, parentStructure.getParentStructureId(), elements);
530    
531                    Document document = SAXReaderUtil.read(parentStructure.getXsd());
532    
533                    Element rootElement = document.getRootElement();
534    
535                    elements.addAll(rootElement.elements());
536            }
537    
538            protected JournalStructure getParentStructure(
539                            long groupId, String parentStructureId)
540                    throws PortalException, SystemException {
541    
542                    JournalStructure parentStructure =
543                            journalStructurePersistence.fetchByG_S(groupId, parentStructureId);
544    
545                    if (parentStructure != null) {
546                            return parentStructure;
547                    }
548    
549                    Group group = groupPersistence.findByPrimaryKey(groupId);
550    
551                    Group companyGroup = groupLocalService.getCompanyGroup(
552                            group.getCompanyId());
553    
554                    if (groupId != companyGroup.getGroupId()) {
555                            parentStructure = journalStructurePersistence.findByG_S(
556                                    companyGroup.getGroupId(), parentStructureId);
557                    }
558    
559                    return parentStructure;
560            }
561    
562            protected void validate(List<Element> elements, Set<String> elNames)
563                    throws PortalException {
564    
565                    for (Element element : elements) {
566                            if (element.getName().equals("meta-data")) {
567                                    continue;
568                            }
569    
570                            String elName = element.attributeValue("name", StringPool.BLANK);
571                            String elType = element.attributeValue("type", StringPool.BLANK);
572    
573                            if (Validator.isNull(elName) ||
574                                    elName.startsWith(JournalStructureConstants.RESERVED)) {
575    
576                                    throw new StructureXsdException();
577                            }
578                            else {
579                                    String completePath = elName;
580    
581                                    Element parentElement = element.getParent();
582    
583                                    while (!parentElement.isRootElement()) {
584                                            completePath =
585                                                    parentElement.attributeValue("name", StringPool.BLANK) +
586                                                            StringPool.SLASH + completePath;
587    
588                                            parentElement = parentElement.getParent();
589                                    }
590    
591                                    String elNameLowerCase = completePath.toLowerCase();
592    
593                                    if (elNames.contains(elNameLowerCase)) {
594                                            throw new DuplicateStructureElementException();
595                                    }
596                                    else {
597                                            elNames.add(elNameLowerCase);
598                                    }
599                            }
600    
601                            if (Validator.isNull(elType)) {
602                                    throw new StructureXsdException();
603                            }
604    
605                            validate(element.elements(), elNames);
606                    }
607            }
608    
609            protected void validate(
610                            long groupId, String structureId, boolean autoStructureId,
611                            String parentStructureId, Map<Locale, String> nameMap, String xsd)
612                    throws PortalException, SystemException {
613    
614                    if (!autoStructureId) {
615                            validateStructureId(structureId);
616    
617                            JournalStructure structure = journalStructurePersistence.fetchByG_S(
618                                    groupId, structureId);
619    
620                            if (structure != null) {
621                                    throw new DuplicateStructureIdException();
622                            }
623                    }
624    
625                    validateParentStructureId(groupId, structureId, parentStructureId);
626                    validate(groupId, parentStructureId, nameMap, xsd);
627            }
628    
629            protected void validate(
630                            long groupId, String parentStructureId, Map<Locale, String> nameMap,
631                            String xsd)
632                    throws PortalException {
633    
634                    Locale locale = LocaleUtil.getDefault();
635    
636                    if (nameMap.isEmpty() || Validator.isNull(nameMap.get(locale))) {
637                            throw new StructureNameException();
638                    }
639    
640                    if (Validator.isNull(xsd)) {
641                            throw new StructureXsdException();
642                    }
643                    else {
644                            try {
645                                    List<Element> elements = new ArrayList<Element>();
646    
647                                    appendParentStructureElements(
648                                            groupId, parentStructureId, elements);
649    
650                                    Document document = SAXReaderUtil.read(xsd);
651    
652                                    Element rootElement = document.getRootElement();
653    
654                                    if (rootElement.elements().isEmpty()) {
655                                            throw new StructureXsdException();
656                                    }
657    
658                                    elements.addAll(rootElement.elements());
659    
660                                    Set<String> elNames = new HashSet<String>();
661    
662                                    validate(elements, elNames);
663                            }
664                            catch (DuplicateStructureElementException dsee) {
665                                    throw dsee;
666                            }
667                            catch (StructureXsdException sxe) {
668                                    throw sxe;
669                            }
670                            catch (Exception e) {
671                                    throw new StructureXsdException();
672                            }
673                    }
674            }
675    
676            protected void validateParentStructureId(
677                            long groupId, String structureId, String parentStructureId)
678                    throws PortalException, SystemException {
679    
680                    if (Validator.isNull(parentStructureId)) {
681                            return;
682                    }
683    
684                    if (parentStructureId.equals(structureId)) {
685                            throw new StructureInheritanceException();
686                    }
687    
688                    JournalStructure parentStructure = getParentStructure(
689                            groupId, parentStructureId);
690    
691                    while (parentStructure != null) {
692                            if ((parentStructure != null) &&
693                                    (parentStructure.getStructureId().equals(structureId) ||
694                                     parentStructure.getParentStructureId().equals(structureId))) {
695    
696                                    throw new StructureInheritanceException();
697                            }
698    
699                            try {
700                                    parentStructure = getParentStructure(
701                                            groupId, parentStructure.getParentStructureId());
702                            }
703                            catch (NoSuchStructureException nsse) {
704                                    break;
705                            }
706                    }
707            }
708    
709            protected void validateStructureId(String structureId)
710                    throws PortalException {
711    
712                    if (Validator.isNull(structureId) ||
713                            Validator.isNumber(structureId) ||
714                            (structureId.indexOf(CharPool.SPACE) != -1)) {
715    
716                            throw new StructureIdException();
717                    }
718            }
719    
720            private static Log _log = LogFactoryUtil.getLog(
721                    JournalStructureLocalServiceImpl.class);
722    
723    }