001
014
015 package com.liferay.portal.service.impl;
016
017 import com.liferay.portal.LayoutFriendlyURLException;
018 import com.liferay.portal.LayoutFriendlyURLsException;
019 import com.liferay.portal.LayoutNameException;
020 import com.liferay.portal.LayoutParentLayoutIdException;
021 import com.liferay.portal.LayoutTypeException;
022 import com.liferay.portal.NoSuchLayoutException;
023 import com.liferay.portal.kernel.bean.BeanReference;
024 import com.liferay.portal.kernel.bean.IdentifiableBean;
025 import com.liferay.portal.kernel.exception.PortalException;
026 import com.liferay.portal.kernel.language.LanguageUtil;
027 import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
028 import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
029 import com.liferay.portal.kernel.util.LocaleUtil;
030 import com.liferay.portal.kernel.util.StringPool;
031 import com.liferay.portal.kernel.util.StringUtil;
032 import com.liferay.portal.kernel.util.Validator;
033 import com.liferay.portal.model.Group;
034 import com.liferay.portal.model.Layout;
035 import com.liferay.portal.model.LayoutConstants;
036 import com.liferay.portal.model.LayoutFriendlyURL;
037 import com.liferay.portal.model.LayoutSet;
038 import com.liferay.portal.model.LayoutSetPrototype;
039 import com.liferay.portal.model.LayoutType;
040 import com.liferay.portal.model.LayoutTypeController;
041 import com.liferay.portal.model.ResourceConstants;
042 import com.liferay.portal.model.Role;
043 import com.liferay.portal.model.RoleConstants;
044 import com.liferay.portal.model.impl.LayoutImpl;
045 import com.liferay.portal.security.permission.ActionKeys;
046 import com.liferay.portal.service.PortletLocalServiceUtil;
047 import com.liferay.portal.service.ResourcePermissionLocalService;
048 import com.liferay.portal.service.RoleLocalServiceUtil;
049 import com.liferay.portal.service.persistence.LayoutFriendlyURLPersistence;
050 import com.liferay.portal.service.persistence.LayoutPersistence;
051 import com.liferay.portal.service.persistence.LayoutSetPersistence;
052 import com.liferay.portal.util.LayoutTypeControllerTracker;
053 import com.liferay.portal.util.Portal;
054 import com.liferay.portal.util.PortalUtil;
055 import com.liferay.portal.util.comparator.LayoutPriorityComparator;
056 import com.liferay.portlet.sites.util.SitesUtil;
057
058 import java.util.HashMap;
059 import java.util.List;
060 import java.util.Locale;
061 import java.util.Map;
062
063
066 public class LayoutLocalServiceHelper implements IdentifiableBean {
067
068 @Override
069 public String getBeanIdentifier() {
070 return _beanIdentifier;
071 }
072
073 public String getFriendlyURL(
074 long groupId, boolean privateLayout, long layoutId, String name,
075 String friendlyURL)
076 throws PortalException {
077
078 friendlyURL = getFriendlyURL(friendlyURL);
079
080 if (Validator.isNotNull(friendlyURL)) {
081 return friendlyURL;
082 }
083
084 friendlyURL = StringPool.SLASH + getFriendlyURL(name);
085
086 String originalFriendlyURL = friendlyURL;
087
088 for (int i = 1;; i++) {
089 try {
090 validateFriendlyURL(
091 groupId, privateLayout, layoutId, friendlyURL);
092
093 break;
094 }
095 catch (LayoutFriendlyURLException lfurle) {
096 int type = lfurle.getType();
097
098 if (type == LayoutFriendlyURLException.DUPLICATE) {
099 friendlyURL = originalFriendlyURL + i;
100 }
101 else {
102 friendlyURL = StringPool.SLASH + layoutId;
103
104 break;
105 }
106 }
107 }
108
109 return friendlyURL;
110 }
111
112 public String getFriendlyURL(String friendlyURL) {
113 return FriendlyURLNormalizerUtil.normalize(friendlyURL);
114 }
115
116 public Map<Locale, String> getFriendlyURLMap(
117 long groupId, boolean privateLayout, long layoutId, String name,
118 Map<Locale, String> friendlyURLMap)
119 throws PortalException {
120
121 Map<Locale, String> newFriendlyURLMap = new HashMap<>();
122
123 for (Locale locale : LanguageUtil.getAvailableLocales(groupId)) {
124 String friendlyURL = friendlyURLMap.get(locale);
125
126 if (Validator.isNotNull(friendlyURL)) {
127 friendlyURL = getFriendlyURL(
128 groupId, privateLayout, layoutId, name, friendlyURL);
129
130 newFriendlyURLMap.put(locale, friendlyURL);
131 }
132 }
133
134 Locale siteDefaultLocale = LocaleUtil.getSiteDefault();
135
136 if (newFriendlyURLMap.isEmpty() ||
137 Validator.isNull(newFriendlyURLMap.get(siteDefaultLocale))) {
138
139 String friendlyURL = getFriendlyURL(
140 groupId, privateLayout, layoutId, name, StringPool.BLANK);
141
142 newFriendlyURLMap.put(siteDefaultLocale, friendlyURL);
143 }
144
145 return newFriendlyURLMap;
146 }
147
148 public int getNextPriority(
149 long groupId, boolean privateLayout, long parentLayoutId,
150 String sourcePrototypeLayoutUuid, int defaultPriority) {
151
152 try {
153 int priority = defaultPriority;
154
155 if (priority < 0) {
156 Layout layout = layoutPersistence.findByG_P_P_First(
157 groupId, privateLayout, parentLayoutId,
158 new LayoutPriorityComparator(false));
159
160 priority = layout.getPriority() + 1;
161 }
162
163 if ((priority < _PRIORITY_BUFFER) &&
164 Validator.isNull(sourcePrototypeLayoutUuid)) {
165
166 LayoutSet layoutSet = layoutSetPersistence.fetchByG_P(
167 groupId, privateLayout);
168
169 if (Validator.isNotNull(
170 layoutSet.getLayoutSetPrototypeUuid()) &&
171 layoutSet.isLayoutSetPrototypeLinkEnabled()) {
172
173 priority = priority + _PRIORITY_BUFFER;
174 }
175 }
176
177 return priority;
178 }
179 catch (NoSuchLayoutException nsle) {
180 return 0;
181 }
182 }
183
184 public long getParentLayoutId(
185 long groupId, boolean privateLayout, long parentLayoutId) {
186
187 if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
188
189
190
191 Layout parentLayout = layoutPersistence.fetchByG_P_L(
192 groupId, privateLayout, parentLayoutId);
193
194 if (parentLayout == null) {
195 parentLayoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;
196 }
197 }
198
199 return parentLayoutId;
200 }
201
202 public boolean hasLayoutSetPrototypeLayout(
203 LayoutSetPrototype layoutSetPrototype, String layoutUuid)
204 throws PortalException {
205
206 Layout layout = layoutPersistence.fetchByUUID_G_P(
207 layoutUuid, layoutSetPrototype.getGroupId(), true);
208
209 if (layout != null) {
210 return true;
211 }
212
213 return false;
214 }
215
216 @Override
217 public void setBeanIdentifier(String beanIdentifier) {
218 _beanIdentifier = beanIdentifier;
219 }
220
221 public void validate(
222 long groupId, boolean privateLayout, long layoutId,
223 long parentLayoutId, String name, String type, boolean hidden,
224 Map<Locale, String> friendlyURLMap)
225 throws PortalException {
226
227 validateName(name);
228
229 boolean firstLayout = false;
230
231 if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
232 List<Layout> layouts = layoutPersistence.findByG_P_P(
233 groupId, privateLayout, parentLayoutId, 0, 1);
234
235 if (layouts.isEmpty()) {
236 firstLayout = true;
237 }
238 else {
239 long firstLayoutId = layouts.get(0).getLayoutId();
240
241 if (firstLayoutId == layoutId) {
242 firstLayout = true;
243 }
244 }
245 }
246 else {
247
248
249
250
251 Layout parentLayout = layoutPersistence.findByG_P_L(
252 groupId, privateLayout, parentLayoutId);
253
254 if (!SitesUtil.isLayoutSortable(parentLayout)) {
255 throw new LayoutParentLayoutIdException(
256 LayoutParentLayoutIdException.NOT_SORTABLE);
257 }
258 }
259
260 if (firstLayout) {
261 validateFirstLayout(type);
262 }
263
264 LayoutTypeController layoutTypeController =
265 LayoutTypeControllerTracker.getLayoutTypeController(type);
266
267 if (!layoutTypeController.isParentable()) {
268 if (layoutPersistence.countByG_P_P(
269 groupId, privateLayout, layoutId) > 0) {
270
271 throw new LayoutTypeException(
272 LayoutTypeException.NOT_PARENTABLE);
273 }
274 }
275
276 validateFriendlyURLs(groupId, privateLayout, layoutId, friendlyURLMap);
277 }
278
279 public void validateFirstLayout(Layout layout) throws PortalException {
280 Group group = layout.getGroup();
281
282 if (group.isGuest() && layout.isPublicLayout() &&
283 !hasGuestViewPermission(layout)) {
284
285 LayoutTypeException lte = new LayoutTypeException(
286 LayoutTypeException.FIRST_LAYOUT_PERMISSION);
287
288 throw lte;
289 }
290
291 validateFirstLayout(layout.getType());
292 }
293
294 public void validateFirstLayout(String type) throws PortalException {
295 LayoutTypeController layoutTypeController =
296 LayoutTypeControllerTracker.getLayoutTypeController(type);
297
298 if (Validator.isNull(type) || !layoutTypeController.isFirstPageable()) {
299 LayoutTypeException lte = new LayoutTypeException(
300 LayoutTypeException.FIRST_LAYOUT);
301
302 lte.setLayoutType(type);
303
304 throw lte;
305 }
306 }
307
308 public void validateFriendlyURL(
309 long groupId, boolean privateLayout, long layoutId,
310 String friendlyURL)
311 throws PortalException {
312
313 if (Validator.isNull(friendlyURL)) {
314 return;
315 }
316
317 int exceptionType = LayoutImpl.validateFriendlyURL(friendlyURL);
318
319 if (exceptionType != -1) {
320 throw new LayoutFriendlyURLException(exceptionType);
321 }
322
323 List<LayoutFriendlyURL> layoutFriendlyURLs =
324 layoutFriendlyURLPersistence.findByG_P_F(
325 groupId, privateLayout, friendlyURL);
326
327 for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
328 Layout layout = layoutPersistence.findByPrimaryKey(
329 layoutFriendlyURL.getPlid());
330
331 if (layout.getLayoutId() != layoutId) {
332 LayoutFriendlyURLException lfurle =
333 new LayoutFriendlyURLException(
334 LayoutFriendlyURLException.DUPLICATE);
335
336 lfurle.setDuplicateClassPK(layout.getPlid());
337 lfurle.setDuplicateClassName(Layout.class.getName());
338
339 throw lfurle;
340 }
341 }
342
343 LayoutImpl.validateFriendlyURLKeyword(friendlyURL);
344
345 if (friendlyURL.contains(Portal.FRIENDLY_URL_SEPARATOR)) {
346 LayoutFriendlyURLException lfurle = new LayoutFriendlyURLException(
347 LayoutFriendlyURLException.KEYWORD_CONFLICT);
348
349 lfurle.setKeywordConflict(Portal.FRIENDLY_URL_SEPARATOR);
350
351 throw lfurle;
352 }
353
354 List<FriendlyURLMapper> friendlyURLMappers =
355 PortletLocalServiceUtil.getFriendlyURLMappers();
356
357 for (FriendlyURLMapper friendlyURLMapper : friendlyURLMappers) {
358 if (friendlyURLMapper.isCheckMappingWithPrefix()) {
359 continue;
360 }
361
362 String mapping = StringPool.SLASH + friendlyURLMapper.getMapping();
363
364 if (friendlyURL.contains(mapping + StringPool.SLASH) ||
365 friendlyURL.endsWith(mapping)) {
366
367 LayoutFriendlyURLException lfurle =
368 new LayoutFriendlyURLException(
369 LayoutFriendlyURLException.KEYWORD_CONFLICT);
370
371 lfurle.setKeywordConflict(friendlyURLMapper.getMapping());
372
373 throw lfurle;
374 }
375 }
376
377 for (Locale locale : LanguageUtil.getAvailableLocales()) {
378 String languageId = StringUtil.toLowerCase(
379 LocaleUtil.toLanguageId(locale));
380
381 String i18nPathLanguageId =
382 StringPool.SLASH +
383 PortalUtil.getI18nPathLanguageId(locale, languageId);
384
385 if (friendlyURL.startsWith(i18nPathLanguageId + StringPool.SLASH) ||
386 friendlyURL.startsWith(
387 StringPool.SLASH + languageId + StringPool.SLASH) ||
388 friendlyURL.endsWith(i18nPathLanguageId) ||
389 friendlyURL.endsWith(StringPool.SLASH + languageId)) {
390
391 LayoutFriendlyURLException lfurle =
392 new LayoutFriendlyURLException(
393 LayoutFriendlyURLException.KEYWORD_CONFLICT);
394
395 lfurle.setKeywordConflict(i18nPathLanguageId);
396
397 throw lfurle;
398 }
399 }
400
401 String layoutIdFriendlyURL = friendlyURL.substring(1);
402
403 if (Validator.isNumber(layoutIdFriendlyURL) &&
404 !layoutIdFriendlyURL.equals(String.valueOf(layoutId))) {
405
406 LayoutFriendlyURLException lfurle = new LayoutFriendlyURLException(
407 LayoutFriendlyURLException.POSSIBLE_DUPLICATE);
408
409 lfurle.setKeywordConflict(layoutIdFriendlyURL);
410
411 throw lfurle;
412 }
413 }
414
415 public void validateFriendlyURLs(
416 long groupId, boolean privateLayout, long layoutId,
417 Map<Locale, String> friendlyURLMap)
418 throws PortalException {
419
420 LayoutFriendlyURLsException layoutFriendlyURLsException = null;
421
422 for (Map.Entry<Locale, String> entry : friendlyURLMap.entrySet()) {
423 try {
424 String friendlyURL = entry.getValue();
425
426 validateFriendlyURL(
427 groupId, privateLayout, layoutId, friendlyURL);
428 }
429 catch (LayoutFriendlyURLException lfurle) {
430 Locale locale = entry.getKey();
431
432 if (layoutFriendlyURLsException == null) {
433 layoutFriendlyURLsException =
434 new LayoutFriendlyURLsException(lfurle);
435 }
436 else {
437 layoutFriendlyURLsException.addSuppressed(lfurle);
438 }
439
440 layoutFriendlyURLsException.addLocalizedException(
441 locale, lfurle);
442 }
443 }
444
445 if (layoutFriendlyURLsException != null) {
446 throw layoutFriendlyURLsException;
447 }
448 }
449
450 public void validateName(String name) throws PortalException {
451 if (Validator.isNull(name)) {
452 throw new LayoutNameException();
453 }
454 }
455
456 public void validateName(String name, String languageId)
457 throws PortalException {
458
459 String defaultLanguageId = LocaleUtil.toLanguageId(
460 LocaleUtil.getSiteDefault());
461
462 if (defaultLanguageId.equals(languageId)) {
463 validateName(name);
464 }
465 }
466
467 public void validateParentLayoutId(
468 long groupId, boolean privateLayout, long layoutId,
469 long parentLayoutId)
470 throws PortalException {
471
472 Layout layout = layoutPersistence.findByG_P_L(
473 groupId, privateLayout, layoutId);
474
475 if (parentLayoutId == layout.getParentLayoutId()) {
476 return;
477 }
478
479
480
481 if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
482 return;
483 }
484
485
486
487 Layout parentLayout = layoutPersistence.findByG_P_L(
488 groupId, privateLayout, parentLayoutId);
489
490 LayoutType parentLayoutType = parentLayout.getLayoutType();
491
492 if (!parentLayoutType.isParentable()) {
493 throw new LayoutParentLayoutIdException(
494 LayoutParentLayoutIdException.NOT_PARENTABLE);
495 }
496
497
498
499
500 if (!SitesUtil.isLayoutSortable(parentLayout)) {
501 throw new LayoutParentLayoutIdException(
502 LayoutParentLayoutIdException.NOT_SORTABLE);
503 }
504
505
506
507 if (PortalUtil.isLayoutDescendant(layout, parentLayoutId)) {
508 throw new LayoutParentLayoutIdException(
509 LayoutParentLayoutIdException.SELF_DESCENDANT);
510 }
511
512
513
514 if (layout.getParentLayoutId() ==
515 LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
516
517 List<Layout> layouts = layoutPersistence.findByG_P_P(
518 groupId, privateLayout,
519 LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, 0, 2);
520
521
522
523
524 long firstLayoutId = layouts.get(0).getLayoutId();
525
526 if (firstLayoutId == layoutId) {
527 Layout secondLayout = layouts.get(1);
528
529 LayoutType layoutType = secondLayout.getLayoutType();
530
531 if (Validator.isNull(secondLayout.getType()) ||
532 !layoutType.isFirstPageable()) {
533
534 throw new LayoutParentLayoutIdException(
535 LayoutParentLayoutIdException.FIRST_LAYOUT_TYPE);
536 }
537 }
538 }
539 }
540
541 protected boolean hasGuestViewPermission(Layout layout)
542 throws PortalException {
543
544 Role role = RoleLocalServiceUtil.getRole(
545 layout.getCompanyId(), RoleConstants.GUEST);
546
547 return resourcePermissionLocalService.hasResourcePermission(
548 layout.getCompanyId(), Layout.class.getName(),
549 ResourceConstants.SCOPE_INDIVIDUAL,
550 String.valueOf(layout.getPlid()), role.getRoleId(),
551 ActionKeys.VIEW);
552 }
553
554 @BeanReference(type = LayoutFriendlyURLPersistence.class)
555 protected LayoutFriendlyURLPersistence layoutFriendlyURLPersistence;
556
557 @BeanReference(type = LayoutPersistence.class)
558 protected LayoutPersistence layoutPersistence;
559
560 @BeanReference(type = LayoutSetPersistence.class)
561 protected LayoutSetPersistence layoutSetPersistence;
562
563 @BeanReference(type = ResourcePermissionLocalService.class)
564 protected ResourcePermissionLocalService resourcePermissionLocalService;
565
566 private static final int _PRIORITY_BUFFER = 1000000;
567
568 private String _beanIdentifier;
569
570 }