/*******************************************************************************
* Copyright (c) 2010-2014 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.skalli.view.internal.filter;
import java.io.IOException;
import java.net.URI;
import java.text.MessageFormat;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.eclipse.skalli.model.Project;
import org.eclipse.skalli.model.Severity;
import org.eclipse.skalli.services.ServiceFilter;
import org.eclipse.skalli.services.Services;
import org.eclipse.skalli.services.favorites.Favorites;
import org.eclipse.skalli.services.favorites.FavoritesService;
import org.eclipse.skalli.services.issues.Issues;
import org.eclipse.skalli.services.issues.IssuesService;
import org.eclipse.skalli.services.template.ProjectTemplate;
import org.eclipse.skalli.services.template.ProjectTemplateService;
import org.eclipse.skalli.services.validation.ValidationService;
import org.eclipse.skalli.view.Consts;
import org.eclipse.skalli.view.ext.InfoBox;
import org.eclipse.skalli.view.ext.ProjectContextLink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This filter reads the following attributes:
* <ul>
* <li>"{@value Consts#ATTRIBUTE_USERID}" - the identifier of the logged in user; if not defined: anonymous user.</li>
* <li>"{@value Consts#ATTRIBUTE_PROJECT}" - the project, or <code>null</code> in case the project is to be created.</li>
* <li>"{@value Consts#ATTRIBUTE_PROJECTADMIN}" - <code>true</code>, if the logged in user is project administrator,
* <code>false</code> otherwise.</li>
* </ul>
* This filter sets the following attributes:
* <ul>
* <li>"{@value Consts#ATTRIBUTE_WINDOWNAME}" - the name of the Vaadin window, either the project's id, or the
* project's uuid for deleted projects. If the project is to be created, the path info from the request is set
* as window name.</li>
* <li>"{@value Consts#ATTRIBUTE_APP_URI}" - the <tt>appUri</tt> parameter passed to Vaadin,
* i.e. <tt>/vprojects/<windowName></tt>. In edit mode, the suffix <tt>/edit</tt> is appended.</li>
* <li>"{@value Consts#ATTRIBUTE_EDITMODE}" - <code>true</code>, if the project is to be edited.</li>
* </ul>
* <p>
* This filter sets the following additional attributes if the request attribute "{@value Consts#ATTRIBUTE_PROJECT}"
* is defined:
* <ul>
* <li>"{@value Consts#ATTRIBUTE_PROJECTTEMPLATE}" - the {@link ProjectTemplate} assigned to the project.</li>
* <li>"{@value Consts#ATTRIBUTE_NATURE}" - the nature of the project.</li>
* </ul>
* This filter sets the following additional attributes if the request attributes "{@value Consts#ATTRIBUTE_PROJECT}"
* and "{@value Consts#ATTRIBUTE_USERID}" are defined:
* <ul>
* <li>"{@value Consts#ATTRIBUTE_FAVORITES}" - the favorites of the logged in user.</li>
* <li>"{@value Consts#ATTRIBUTE_SHOW_ISSUES}" - <code>true</code>, if the logged in user is allowed to see the issues
* of the project, <code>false</code> otherwise. A user must be administrator of the project or administrator of
* any project in the project's parent hierarchy to see issues.</li>
* <li>"{@value Consts#ATTRIBUTE_ISSUES}" - the {@link Issues issues} of the project.</li>
* <li>"{@value Consts#ATTRIBUTE_MAX_SEVERITY}" - the maximum severity found in the project issues.</li>
* <li>"{@value Consts#ATTRIBUTE_PROJECTCONTEXTLINKS}" - the context links to be display in the navigation bar.</li>
* </ul>
*/
public class ProjectDetailsFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(ProjectDetailsFilter.class);
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String userId = (String) request.getAttribute(Consts.ATTRIBUTE_USERID);
Project project = (Project) request.getAttribute(Consts.ATTRIBUTE_PROJECT);
boolean isProjectAdmin = BooleanUtils.toBoolean((Boolean)request.getAttribute(Consts.ATTRIBUTE_PROJECTADMIN));
boolean isProjectAdminInParentChain =
BooleanUtils.toBoolean((Boolean)request.getAttribute(Consts.ATTRIBUTE_PARENTPROJECTADMIN));
String action = request.getParameter(Consts.PARAM_ACTION);
String windowName = StringUtils.strip(httpRequest.getPathInfo(), "/"); //$NON-NLS-1$
if (project != null) {
if (!project.isDeleted()) {
windowName = project.getProjectId();
} else {
windowName = project.getUuid().toString();
}
ProjectTemplateService templateService = Services.getRequiredService(ProjectTemplateService.class);
ProjectTemplate projectTemplate = templateService.getProjectTemplateById(project.getProjectTemplateId());
request.setAttribute(Consts.ATTRIBUTE_PROJECTTEMPLATE, projectTemplate);
request.setAttribute(Consts.ATTRIBUTE_NATURE, projectTemplate.getProjectNature().toString());
if (userId != null) {
FavoritesService favoritesService = Services.getService(FavoritesService.class);
Favorites favorites = null;
if (favoritesService == null) {
favorites = new Favorites(userId);
} else {
favorites = favoritesService.getFavorites(userId);
}
request.setAttribute(Consts.ATTRIBUTE_FAVORITES, favorites.asMap());
boolean showIssues = isProjectAdmin || isProjectAdminInParentChain;
request.setAttribute(Consts.ATTRIBUTE_SHOW_ISSUES, isProjectAdmin);
if (showIssues) {
IssuesService issuesService = Services.getService(IssuesService.class);
if (issuesService != null) {
if (Consts.PARAM_VALUE_VALIDATE.equals(action)) {
ValidationService validationService = Services.getService(ValidationService.class);
if (validationService != null) {
validationService.validate(Project.class, project.getUuid(), Severity.INFO, userId);
}
}
Issues issues = issuesService.getByUUID(project.getUuid());
if (issues != null && issues.hasIssues()) {
request.setAttribute(Consts.ATTRIBUTE_ISSUES, issues);
request.setAttribute(Consts.ATTRIBUTE_MAX_SEVERITY, issues.getIssues().first().getSeverity()
.name());
}
}
}
request.setAttribute(Consts.ATTRIBUTE_PROJECTCONTEXTLINKS,
getOrderedVisibleProjectContextLinks(project, userId));
}
String pathInfo = httpRequest.getPathInfo();
if (pathInfo != null) {
int infoBoxIndex = pathInfo.indexOf(Consts.URL_INFOBOXES);
if (infoBoxIndex > 0) {
if (StringUtils.isNotBlank(action)) {
String infoBoxShortName = pathInfo.substring(infoBoxIndex + Consts.URL_INFOBOXES.length());
if (infoBoxShortName.startsWith(FilterUtil.PATH_SEPARATOR)) {
infoBoxShortName = infoBoxShortName.substring(1);
}
filterInfobox(project, infoBoxShortName, action, userId);
}
}
}
}
request.setAttribute(Consts.ATTRIBUTE_WINDOWNAME, windowName);
request.setAttribute(Consts.ATTRIBUTE_EDITMODE, false);
String appUri = Consts.URL_VAADIN_PROJECTS + windowName;
if (StringUtils.isNotBlank(action)) {
if (action.equals(Consts.PARAM_VALUE_EDIT)) {
request.setAttribute(Consts.ATTRIBUTE_EDITMODE, true);
appUri = appUri + "/edit"; //$NON-NLS-1$
}
}
request.setAttribute(Consts.ATTRIBUTE_APP_URI, appUri);
// proceed along the chain
chain.doFilter(request, response);
}
private void filterInfobox(final Project project, String infoBoxShortName, String action, final String userId) {
final boolean performAllInfoBoxes = StringUtils.isBlank(infoBoxShortName) ? true : false;
Set<InfoBox> infoboxes = Services.getServices(InfoBox.class,
new ServiceFilter<InfoBox>() {
@Override
public boolean accept(InfoBox infoBox) {
return infoBox.isVisible(project, userId);
}
});
for (InfoBox infoBox : infoboxes) {
if (performAllInfoBoxes || infoBoxShortName.equalsIgnoreCase(infoBox.getShortName())) {
infoBox.perform(action, project, userId);
}
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
/**
* returns a sorted set of links in context of the current project.
*/
private Set<Link> getOrderedVisibleProjectContextLinks(Project project, final String userId) {
final Project p = project;
Set<ProjectContextLink> set = Services.getServices(ProjectContextLink.class,
new ServiceFilter<ProjectContextLink>() {
@Override
public boolean accept(ProjectContextLink contextLink) {
return contextLink.isVisible(p, userId);
}
});
Set<Link> result = new TreeSet<Link>(new Comparator<Link>() {
@Override
public int compare(Link l1, Link l2) {
if (l1.getPositionWeight() != l2.getPositionWeight()) {
return new Float(l1.getPositionWeight()).compareTo(l2.getPositionWeight());
} else {
// in case the position weight is equal, compare by link caption
// to prevent that one of both links is sorted out of the result set
return (l1.getCaption().compareTo(l2.getCaption()));
}
}
});
for (ProjectContextLink contextLink : set) {
if (StringUtils.isBlank(contextLink.getCaption(project))) {
LOG.warn(MessageFormat.format(
"instance of {0} returned null or blank when calling method getCaption(project) with projectId={1}",
contextLink.getClass(), project.getProjectId()));
} else if (contextLink.getUri(project) == null) {
LOG.warn(MessageFormat.format(
"instance of {0} returned null when calling method getUri(project) with projectId={1}",
contextLink.getClass(), project.getProjectId()));
} else {
Link link = new Link();
// set the class name as id, this can be used for UI testing
link.setId(contextLink.getClass().getName());
link.setCaption(contextLink.getCaption(project));
link.setUri(contextLink.getUri(project));
link.setPositionWeight(contextLink.getPositionWeight());
result.add(link);
}
}
return result;
}
public class Link {
private String caption;
private URI uri;
private float positionWeight;
private String id;
public String getCaption() {
return caption;
}
public void setCaption(String caption) {
this.caption = caption;
}
public URI getUri() {
return uri;
}
public void setUri(URI uri) {
this.uri = uri;
}
public float getPositionWeight() {
return positionWeight;
}
public void setPositionWeight(float positionWeight) {
this.positionWeight = positionWeight;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
}