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