Model for item lists

pull/10/head
Jens Pelzetter 2021-10-30 16:11:34 +02:00
parent 8b3f18582f
commit c689ed536c
12 changed files with 850 additions and 19 deletions

View File

@ -29,14 +29,15 @@ import javax.inject.Inject;
* @param <T>
* @param <M>
*/
public abstract class AbstractContentItemListModelBuilder<T extends ContentItem, M extends AbstractContentItemListItemModel>
public abstract class AbstractContentItemListItemModelBuilder<T extends ContentItem, M extends AbstractContentItemListItemModel>
implements ContentItemListItemModelBuilder<T, M> {
@Inject
private GlobalizationHelper globalizationHelper;
@Override
public M buildListItemModel(final T contentItem) {
@SuppressWarnings("unchecked")
public M buildListItemModel(final ContentItem contentItem) {
final M model = buildModel();
model.setDescription(
globalizationHelper.getValueFromLocalizedString(
@ -53,7 +54,7 @@ public abstract class AbstractContentItemListModelBuilder<T extends ContentItem,
)
);
addProperties(contentItem, model);
addProperties((T) contentItem, model);
return model;
}

View File

@ -28,7 +28,7 @@ import javax.enterprise.context.RequestScoped;
*/
@RequestScoped
public class ArticleListItemModelBuilder
extends AbstractContentItemListModelBuilder<Article, ArticleListItemModel> {
extends AbstractContentItemListItemModelBuilder<Article, ArticleListItemModel> {
@Override
protected ArticleListItemModel buildModel() {

View File

@ -28,7 +28,7 @@ import org.librecms.contentsection.ContentItem;
*/
public interface ContentItemListItemModelBuilder<T extends ContentItem, M extends AbstractContentItemListItemModel> {
M buildListItemModel(T contentItem);
M buildListItemModel(ContentItem contentItem);
Class<T> buildsListItemModelFor();

View File

@ -30,7 +30,7 @@ import javax.inject.Inject;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class EventListItemModelBuilder
extends AbstractContentItemListModelBuilder<Event, EventListItemModel> {
extends AbstractContentItemListItemModelBuilder<Event, EventListItemModel> {
@Inject
private GlobalizationHelper globalizationHelper;

View File

@ -20,7 +20,6 @@ package org.librecms.pages.models;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.contentsection.ContentItem;
import org.librecms.contenttypes.Article;
import org.librecms.contenttypes.Event;
import java.time.ZoneId;
@ -47,13 +46,15 @@ public class EventModel {
private GlobalizationHelper globalizationHelper;
public String getTitle() {
return globalizationHelper
.getValueFromLocalizedString(getEvent().getTitle());
return globalizationHelper.getValueFromLocalizedString(
getEvent().getTitle()
);
}
public String getText() {
return globalizationHelper
.getValueFromLocalizedString(getEvent().getText());
return globalizationHelper.getValueFromLocalizedString(
getEvent().getText()
);
}
public String getStartDateTime() {
@ -61,21 +62,23 @@ public class EventModel {
.withZone(ZoneId.systemDefault())
.format(getEvent().getStartDate().toInstant());
}
public String getEndDateTime() {
return DateTimeFormatter.ISO_DATE_TIME
.withZone(ZoneId.systemDefault())
.format(getEvent().getEndDate().toInstant());
}
public String getEventDate() {
return globalizationHelper
.getValueFromLocalizedString(getEvent().getEventDate());
return globalizationHelper.getValueFromLocalizedString(
getEvent().getEventDate()
);
}
public String getLocation() {
return globalizationHelper.
getValueFromLocalizedString(getEvent().getLocation());
return globalizationHelper.getValueFromLocalizedString(
getEvent().getLocation()
);
}
protected Event getEvent() {

View File

@ -0,0 +1,412 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.pages.models;
import com.arsdigita.kernel.KernelConfig;
import org.libreccm.categorization.Categorization;
import org.libreccm.categorization.Category;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.core.UnexpectedErrorException;
import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.security.Permission;
import org.libreccm.security.PermissionChecker;
import org.libreccm.security.Role;
import org.libreccm.security.RoleManager;
import org.libreccm.security.Shiro;
import org.libreccm.security.User;
import org.libreccm.security.UserRepository;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemL10NManager;
import org.librecms.contentsection.ContentItemVersion;
import org.librecms.contentsection.privileges.ItemPrivileges;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPagesItemListModel")
public class ItemListModel {
@Inject
private CategoryModel categoryModel;
@Inject
private ConfigurationManager confManager;
@Inject
private ContentItemL10NManager itemL10NManager;
@Inject
private ContentItemListItemModelBuilders listItemModelBuilders;
@Inject
private GlobalizationHelper globalizationHelper;
@Inject
private EntityManager entityManager;
@Inject
private PermissionChecker permissionChecker;
@Inject
private RoleManager roleManager;
@Inject
private UserRepository userRepo;
@Inject
private Shiro shiro;
@Inject
private PageUrlModel pageUrlModel;
private boolean descending;
private String limitToType;
private List<String> listOrder;
private int pageSize;
private List<? extends AbstractContentItemListItemModel> itemList;
public ItemListModel() {
descending = false;
limitToType = ContentItem.class.getName();
listOrder = List.of(ContentItem.class.getName());
pageSize = 20;
}
public boolean isDescending() {
return descending;
}
public void setDescending(final boolean descending) {
this.descending = descending;
}
public String getLimitToType() {
return limitToType;
}
public void setLimitToType(final String limitToType) {
this.limitToType = limitToType;
}
public List<String> getListOrder() {
return Collections.unmodifiableList(listOrder);
}
public void setListOrder(final List<String> listOrder) {
this.listOrder = new ArrayList<>(listOrder);
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(final int pageSize) {
this.pageSize = pageSize;
}
public int getFirstItem() {
return getOffset(pageSize);
}
public int getListSize() {
return getItems().size();
}
public List<? extends AbstractContentItemListItemModel> getItems() {
if (itemList == null) {
buildList(
buildLimitToType(limitToType),
collectCategories(categoryModel.getCategory()),
listOrder,
pageSize
);
}
return Collections.unmodifiableList(itemList);
}
private void buildList(
final Class<? extends ContentItem> limitToType,
final List<Category> categories,
final List<String> listOrder,
final int pageSize
) {
final CriteriaBuilder criteriaBuilder = entityManager
.getCriteriaBuilder();
final CriteriaQuery<? extends ContentItem> criteriaQuery
= criteriaBuilder
.createQuery(limitToType);
final Root<? extends ContentItem> from = criteriaQuery
.from(limitToType);
final Join<? extends ContentItem, Categorization> catJoin = from
.join("categories");
final Join<? extends ContentItem, Permission> permissionsJoin = from
.join("permissions", JoinType.LEFT);
criteriaQuery
.distinct(true)
.where(
criteriaBuilder.and(
catJoin.get("category").in(categories),
criteriaBuilder.equal(catJoin.get("indexObject"), false),
criteriaBuilder.equal(catJoin.get("type"), ""),
criteriaBuilder.equal(
from.get("version"), ContentItemVersion.LIVE
),
buildPermissionsCheck(
criteriaBuilder, from, permissionsJoin
)
)
);
criteriaQuery.orderBy(
listOrder
.stream()
.map(order -> builderOrder(order, from, criteriaBuilder))
.collect(Collectors.toList())
);
itemList = entityManager
.createQuery(criteriaQuery)
.getResultList()
.stream()
.filter(
item -> itemL10NManager.hasLanguage(
item, globalizationHelper.getNegotiatedLocale()
)
)
.skip(getOffset(pageSize))
.limit(pageSize)
.map(this::buildListItemModel)
.collect(Collectors.toList());
}
private List<Category> collectCategories(final Category category) {
if (category.getSubCategories().isEmpty()) {
return Collections.emptyList();
} else {
final List<Category> categories = new ArrayList<>();
for (final Category subCategory : category.getSubCategories()) {
categories.add(subCategory);
categories.addAll(collectCategories(subCategory));
}
return categories;
}
}
private Class<? extends ContentItem> buildLimitToType(
final String className
) {
if (className == null || className.isBlank()) {
return ContentItem.class;
} else {
final Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException ex) {
throw new UnexpectedErrorException(ex);
}
if (ContentItem.class.isAssignableFrom(clazz)) {
@SuppressWarnings("unchecked")
final Class<? extends ContentItem> type
= (Class<? extends ContentItem>) clazz;
return type;
} else {
throw new UnexpectedErrorException(String
.format(
"The type \"%s\" set in ItemList is not a subtype of "
+ "\"%s\".",
clazz.getName(),
ContentItem.class.getName()));
}
}
}
private Predicate buildPermissionsCheck(
final CriteriaBuilder criteriaBuilder,
final Root<? extends ContentItem> from,
final Join<? extends ContentItem, Permission> permissionsJoin
) {
final List<Role> roles = retrieveCurrentRoles();
final boolean isSystemUser = shiro.isSystemUser();
final boolean isAdmin = permissionChecker.isPermitted("*");
final Predicate permissionsCheck;
if (roles.isEmpty()) {
permissionsCheck = criteriaBuilder
.or(
criteriaBuilder.equal(criteriaBuilder.literal(true),
isSystemUser),
criteriaBuilder.equal(criteriaBuilder.literal(true),
isAdmin)
);
} else {
permissionsCheck = criteriaBuilder
.or(
criteriaBuilder
.and(
criteriaBuilder.in(permissionsJoin.get("grantee"))
.value(roles),
criteriaBuilder
.equal(
permissionsJoin.get("grantedPrivilege"),
criteriaBuilder.selectCase()
.when(
criteriaBuilder.equal(
from.get("version"),
ContentItemVersion.DRAFT),
ItemPrivileges.PREVIEW)
.otherwise(
ItemPrivileges.VIEW_PUBLISHED))
),
criteriaBuilder
.equal(criteriaBuilder.literal(true),
isSystemUser),
criteriaBuilder
.equal(criteriaBuilder.literal(true),
isAdmin)
);
}
return permissionsCheck;
}
private List<Role> retrieveCurrentRoles() {
final Optional<User> user = shiro.getUser();
final List<Role> roles;
if (user.isPresent()) {
final User theUser = userRepo
.findById(user.get().getPartyId())
.orElseThrow(() -> new IllegalArgumentException(String
.format(
"No user with id %d in the database. "
+ "Where did that ID come from?",
user.get().getPartyId())));
roles = roleManager.findAllRolesForUser(theUser);
} else {
final Optional<User> publicUser;
final KernelConfig kernelConfig = confManager
.findConfiguration(KernelConfig.class);
final String principal = (String) shiro
.getPublicUser()
.getPrincipal();
if (kernelConfig.emailIsPrimaryIdentifier()) {
publicUser = userRepo.findByEmailAddress(principal);
} else {
publicUser = userRepo.findByName(principal);
}
if (publicUser.isPresent()) {
roles = roleManager.findAllRolesForUser(publicUser.get());
} else {
roles = Collections.emptyList();
}
}
return roles;
}
private Order builderOrder(
final String order,
final Root<? extends ContentItem> from,
final CriteriaBuilder criteriaBuilder
) {
if (order.endsWith(" ASC")) {
final String colName = order
.substring(0, order.length() - " ASC".length());
return (criteriaBuilder.asc(from.get(colName)));
} else if (order.endsWith(" DESC")) {
final String colName = order
.substring(0, order.length() - " DESC".length());
return criteriaBuilder.desc(from.get(colName));
} else {
return criteriaBuilder.asc(from.get(order));
}
}
private int getOffset(final int pageSize) {
if (pageUrlModel.getQueryParameters().containsKey("page")) {
final String value = pageUrlModel.getQueryParameters().get("page");
if (value.matches("\\d*")) {
final int page = Integer.valueOf(value);
return page * pageSize;
} else {
return 0;
}
} else {
return 0;
}
}
private AbstractContentItemListItemModel buildListItemModel(
final ContentItem contentItem
) {
final ContentItemListItemModelBuilder<?, ?> builder
= listItemModelBuilders.getModelBuilderFor(contentItem.getClass())
.orElseThrow(
() -> new WebApplicationException(
Response
.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(
String.format(
"No ListItemModelBuilder for content item "
+ "type %s available.",
contentItem.getClass().getName()
)
)
.build()
)
);
return builder.buildListItemModel(contentItem);
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.pages.models;
import org.librecms.contenttypes.MultiPartArticle;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class MultiPartArticleListItemModel
extends AbstractContentItemListItemModel {
private String summary;
public String getSummary() {
return summary;
}
protected void setSummary(final String summary) {
this.summary = summary;
}
@Override
public String getType() {
return MultiPartArticle.class.getName();
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.pages.models;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.contenttypes.MultiPartArticle;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class MultiPartArticleListItemModelBuilder
extends AbstractContentItemListItemModelBuilder<MultiPartArticle, MultiPartArticleListItemModel> {
@Inject
private GlobalizationHelper globalizationHelper;
@Override
public Class<MultiPartArticle> buildsListItemModelFor() {
return MultiPartArticle.class;
}
@Override
protected MultiPartArticleListItemModel buildModel() {
return new MultiPartArticleListItemModel();
}
@Override
protected void addProperties(
final MultiPartArticle article,
final MultiPartArticleListItemModel model
) {
super.addProperties(article, model);
model.setSummary(
globalizationHelper.getValueFromLocalizedString(
article.getSummary()
)
);
}
}

View File

@ -0,0 +1,168 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.pages.models;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.contentsection.ContentItem;
import org.librecms.contenttypes.MultiPartArticle;
import org.librecms.contenttypes.MultiPartArticleSection;
import java.util.List;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPagesMultiPartArticleModel")
public class MultiPartArticleModel {
@Inject
private ContentItemModel contentItemModel;
@Inject
private GlobalizationHelper globalizationHelper;
@Inject
private PageUrlModel pageUrlModel;
public String getTitle() {
return globalizationHelper.getValueFromLocalizedString(
getMultiPartArticle().getTitle()
);
}
public String getSummary() {
return globalizationHelper.getValueFromLocalizedString(
getMultiPartArticle().getSummary()
);
}
public List<String> getSectionTitles() {
return getMultiPartArticle()
.getSections()
.stream()
.map(MultiPartArticleSection::getTitle)
.map(globalizationHelper::getValueFromLocalizedString)
.collect(Collectors.toList());
}
public String getCurrentSectionTitle() {
final int currentSection = readCurrentSection();
if (getMultiPartArticle().getSections().size() > currentSection) {
throw new WebApplicationException(
Response
.status(Response.Status.NOT_FOUND)
.entity(
String.format(
"MultiPartArticle %s has not section %d.",
getMultiPartArticle().getDisplayName(),
currentSection
)
)
.build()
);
}
return globalizationHelper.getValueFromLocalizedString(
getMultiPartArticle().getSections().get(currentSection).getTitle()
);
}
public String getCurrentSectionText() {
final int currentSection = readCurrentSection();
if (getMultiPartArticle().getSections().size() > currentSection) {
throw new WebApplicationException(
Response
.status(Response.Status.NOT_FOUND)
.entity(
String.format(
"MultiPartArticle %s has not section %d.",
getMultiPartArticle().getDisplayName(),
currentSection
)
)
.build()
);
}
return globalizationHelper.getValueFromLocalizedString(
getMultiPartArticle().getSections().get(currentSection).getText()
);
}
public List<MultiPartArticleSectionModel> getSections() {
return getMultiPartArticle()
.getSections()
.stream()
.map(this::buildSectionModel)
.collect(Collectors.toList());
}
protected MultiPartArticle getMultiPartArticle() {
final ContentItem contentItem = contentItemModel.getContentItem();
if (contentItem instanceof MultiPartArticle) {
return (MultiPartArticle) contentItem;
} else {
throw new WebApplicationException(
"Current content item is not an MultiPartArticle",
Response
.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Current content item is not an MultiPartArticle.")
.build()
);
}
}
private int readCurrentSection() {
if (pageUrlModel.getPath().matches(".*/@sections/[0-9]*$")) {
final String[] tokens = pageUrlModel.getPath().split("/");
return Integer.valueOf(tokens[tokens.length - 1]) - 1;
} else {
return 0;
}
}
private MultiPartArticleSectionModel buildSectionModel(
final MultiPartArticleSection fromSection
) {
final MultiPartArticleSectionModel model
= new MultiPartArticleSectionModel();
model.setTitle(
globalizationHelper.getValueFromLocalizedString(
fromSection.getTitle()
)
);
model.setText(
globalizationHelper.getValueFromLocalizedString(
fromSection.getText()
)
);
return model;
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.pages.models;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class MultiPartArticleSectionModel {
private String title;
private String text;
public String getTitle() {
return title;
}
protected void setTitle(final String title) {
this.title = title;
}
public String getText() {
return text;
}
protected void setText(final String text) {
this.text = text;
}
}

View File

@ -27,7 +27,7 @@ import java.time.LocalDateTime;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class NewsListItemModelBuilder
extends AbstractContentItemListModelBuilder<News, NewsListItemModel> {
extends AbstractContentItemListItemModelBuilder<News, NewsListItemModel> {
@Override
public Class<News> buildsListItemModelFor() {

View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.pages.models;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/**
* Model initalized by the Pages application containing information about the
* URL requested.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPagesPageUrlModel")
public class PageUrlModel {
private String protocol;
private String host;
private int port;
private String path;
private Map<String, String> queryParameters;
public String getProtocol() {
return protocol;
}
public void setProtocol(final String protocol) {
this.protocol = protocol;
}
public String getHost() {
return host;
}
public void setHost(final String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(final int port) {
this.port = port;
}
public String getPath() {
return path;
}
public void setPath(final String path) {
this.path = path;
}
public PageUrlModel() {
queryParameters = new HashMap<>();
}
public Map<String, String> getQueryParameters() {
return Collections.unmodifiableMap(queryParameters);
}
public void addQueryParameter(final String key, final String value) {
queryParameters.put(key, value);
}
public void setQueryParameters(final Map<String, String> queryParameters) {
this.queryParameters = new HashMap<>(queryParameters);
}
}