Skip to content

Commit

Permalink
Merge branch 'release/3.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
jcarvalho committed Aug 1, 2014
2 parents f4dcd54 + 3984a70 commit 0368a80
Show file tree
Hide file tree
Showing 118 changed files with 1,607 additions and 727 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
language: java
jdk:
- oraclejdk7
- oraclejdk8
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Bennu covers the following core features:
mvn archetype:generate \
-DarchetypeGroupId=org.fenixedu \
-DarchetypeArtifactId=bennu-webapp-archetype \
-DarchetypeVersion=3.2.0 \
-DarchetypeVersion=3.3.0 \
-DarchetypeRepository=https://fenix-ashes.ist.utl.pt/nexus/content/groups/fenix-ashes-maven-repository
```
Make sure to supply the information required by the archetype.
Expand Down Expand Up @@ -53,7 +53,7 @@ Make sure to supply the information required by the archetype.
mvn archetype:generate \
-DarchetypeGroupId=org.fenixedu \
-DarchetypeArtifactId=bennu-project-archetype \
-DarchetypeVersion=3.2.0 \
-DarchetypeVersion=3.3.0 \
-DarchetypeRepository=https://fenix-ashes.ist.utl.pt/nexus/content/groups/fenix-ashes-maven-repository
```

Expand Down
2 changes: 1 addition & 1 deletion bennu-portal/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.fenixedu</groupId>
<artifactId>bennu</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
</parent>

<artifactId>bennu-portal</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.fenixedu.bennu.portal;

import org.fenixedu.commons.configuration.ConfigurationInvocationHandler;
import org.fenixedu.commons.configuration.ConfigurationManager;
import org.fenixedu.commons.configuration.ConfigurationProperty;

public class BennuPortalConfiguration {

@ConfigurationManager(description = "Bennu Portal Configuration")
public static interface ConfigurationProperties {

@ConfigurationProperty(key = "theme.development.mode", defaultValue = "false",
description = "Disables Theme Caching and allows live-reloading of themes")
public Boolean themeDevelopmentMode();

}

public static ConfigurationProperties getConfiguration() {
return ConfigurationInvocationHandler.getConfiguration(ConfigurationProperties.class);
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
package org.fenixedu.bennu.portal.client;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletResponse;

import org.fenixedu.bennu.portal.domain.MenuFunctionality;
import org.fenixedu.bennu.portal.servlet.PortalBackend;
import org.fenixedu.bennu.portal.servlet.SemanticURLHandler;

Expand All @@ -17,14 +12,15 @@ public class ClientSidePortalBackend implements PortalBackend {

@Override
public SemanticURLHandler getSemanticURLHandler() {
return new SemanticURLHandler() {
@Override
public void handleRequest(MenuFunctionality functionality, HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
String forwardUrl =
"/" + functionality.getParent().getPath() + "/"
+ (functionality.getPath().startsWith("#") ? "" : functionality.getPath());
request.getRequestDispatcher(forwardUrl).forward(request, response);
return (functionality, request, response, chain) -> {
String forwardUrl =
"/" + functionality.getParent().getPath() + "/"
+ (functionality.getPath().startsWith("#") ? "" : functionality.getPath());
RequestDispatcher requestDispatcher = request.getRequestDispatcher(forwardUrl);
if (requestDispatcher != null) {
requestDispatcher.forward(request, response);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "No forward url could be processed");
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collector;
import java.util.stream.Stream;

import org.fenixedu.bennu.core.domain.User;
import org.fenixedu.bennu.portal.model.Application;
Expand Down Expand Up @@ -131,6 +133,14 @@ public Set<MenuItem> getOrderedChild() {
return Collections.unmodifiableSet(new TreeSet<>(getChildSet()));
}

/**
* Returns a {@link Set} containing all the children of this container, that are available to the
* current user.
*
* @deprecated
* Use {@link MenuContainer#getUserMenuStream()} and apply a {@link Collector}.
*/
@Deprecated
public Set<MenuItem> getUserMenu() {
return FluentIterable.from(getChildSet()).filter(new Predicate<MenuItem>() {
@Override
Expand All @@ -143,7 +153,11 @@ public boolean apply(MenuItem menu) {
/**
* Returns an {@link Iterable} containing all the child {@link MenuContainer}s of this container, that are available to the
* current user.
*
* @deprecated
* Use {@link MenuContainer#getUserMenuStream()} and apply another filter
*/
@Deprecated
public Iterable<MenuContainer> getAvailableChildContainers() {
return FluentIterable.from(getChildSet()).filter(MenuContainer.class).filter(new Predicate<MenuContainer>() {
@Override
Expand All @@ -153,6 +167,17 @@ public boolean apply(MenuContainer container) {
}).toSortedList(Ordering.natural());
}

/**
* Returns the User Menu as a lazy {@link Stream}. This method is preferred
* to the alternatives (returning {@link Set}), as it allows further optimizations.
*
* @return
* The User's Menu as a Stream
*/
public Stream<MenuItem> getUserMenuStream() {
return getChildSet().stream().filter((item) -> item.isVisible() && item.isItemAvailableForCurrentUser()).sorted();
}

/**
* Deletes this container, as well as all its children.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,25 @@ private PortalConfiguration() {
setApplicationCopyright(new LocalizedString(I18N.getLocale(), "Organization Copyright"));
setHtmlTitle(getApplicationTitle());
setTheme("default");
InputStream stream = this.getClass().getResourceAsStream("/img/bennu-logo.png");
if (stream == null) {
logger.error("Default logo not found in: img/bennu-logo.png");
} else {
try {
try (InputStream stream = this.getClass().getResourceAsStream("/img/logo_bennu.svg")) {
if (stream == null) {
logger.error("Default logo not found in: img/logo_bennu.svg");
} else {
setLogo(ByteStreams.toByteArray(stream));
setLogoType("image/png");
} catch (IOException e) {
logger.error("Default logo could not be read from: img/bennu-logo.png");
setLogoType("image/svg+xml");
}
} catch (IOException e) {
logger.error("Default logo could not be read from: img/logo_bennu.svg");
}

stream = this.getClass().getResourceAsStream("/img/bennu-favicon.png");
if (stream == null) {
logger.error("Default favicon not found in: img/bennu-favicon.png");
} else {
try {
try (InputStream stream = this.getClass().getResourceAsStream("/img/favicon_bennu.png")) {
if (stream == null) {
logger.error("Default favicon not found in: img/favicon_bennu.png");
} else {
setFavicon(ByteStreams.toByteArray(stream));
setFaviconType("image/png");
} catch (IOException e) {
logger.error("Default logo could not be read from: img/bennu-favicon.png");
}
} catch (IOException e) {
logger.error("Default logo could not be read from: img/favicon_bennu.png");
}
new MenuContainer(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class PortalMenuViewer extends PortalConfigurationAdapter {
public JsonElement view(PortalConfiguration configuration, JsonBuilder ctx) {
final JsonObject view = super.view(configuration, ctx).getAsJsonObject();
if (configuration.getMenu() != null) {
view.add("menu", ctx.view(configuration.getMenu().getUserMenu()));
view.add("menu", ctx.view(configuration.getMenu().getUserMenuStream()));
}
return view;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public JsonElement view(MenuItem obj, JsonBuilder ctx) {
if (container.isRoot()) {
json.add("title", ctx.view(PortalConfiguration.getInstance().getApplicationTitle()));
}
json.add("menu", ctx.view(container.getUserMenu()));
json.add("menu", ctx.view(container.getUserMenuStream()));
}
return json;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package org.fenixedu.bennu.portal.servlet;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletResponse;

import org.fenixedu.bennu.portal.domain.MenuFunctionality;
Expand All @@ -18,17 +14,18 @@
*/
public class ForwarderPortalBackend implements PortalBackend {

private static final SemanticURLHandler HANDLER = new SemanticURLHandler() {
@Override
public void handleRequest(MenuFunctionality functionality, HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.getRequestDispatcher(functionality.getItemKey()).forward(request, response);
}
};

@Override
public SemanticURLHandler getSemanticURLHandler() {
return HANDLER;
return (functionality, request, response, chain) -> {
// Remove the functionality, allowing the target to choose the proper one
BennuPortalDispatcher.selectFunctionality(request, null);
RequestDispatcher requestDispatcher = request.getRequestDispatcher(functionality.getItemKey());
if (requestDispatcher != null) {
requestDispatcher.forward(request, response);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "No forward url could be processed");
}
};
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package org.fenixedu.bennu.portal.servlet;

import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Stream;

import com.mitchellbosecke.pebble.error.ParserException;
import com.mitchellbosecke.pebble.error.PebbleException;
import com.mitchellbosecke.pebble.extension.NodeVisitor;
import com.mitchellbosecke.pebble.lexer.Token;
import com.mitchellbosecke.pebble.lexer.TokenStream;
import com.mitchellbosecke.pebble.node.AbstractRenderableNode;
import com.mitchellbosecke.pebble.node.BodyNode;
import com.mitchellbosecke.pebble.node.RenderableNode;
import com.mitchellbosecke.pebble.node.expression.Expression;
import com.mitchellbosecke.pebble.template.EvaluationContext;
import com.mitchellbosecke.pebble.template.PebbleTemplateImpl;
import com.mitchellbosecke.pebble.tokenParser.AbstractTokenParser;
import com.mitchellbosecke.pebble.tokenParser.TokenParser;

/**
* {@link TokenParser} for the 'lazyFor' node.
*
* This node allow lazy iteration over a {@link Stream}, without
* invoking extraneous terminal operations. In practice, this node
* is a wrapper for {@link Stream#forEach(java.util.function.Consumer)}.
*
* Unlike the regular 'for' node, no extra variables are defined, only
* the iteration variable, named in the token's usage.
*
* Accepted arguments are instance of {@link Stream}, {@link Collection} or arrays.
*
* Example:
*
* <pre>
* {% lazyFor item in itemStream %}
* {{item.name}}
* {% endLazyFor %}
* </pre>
*
* @author João Carvalho ([email protected])
*
* @since 3.3
*
*/
public class LazyForTokenParser extends AbstractTokenParser {

@Override
public RenderableNode parse(Token token) throws ParserException {
TokenStream stream = this.parser.getStream();
int lineNumber = token.getLineNumber();

// skip the 'lazyFor' token
stream.next();

// get the iteration variable
String iterationVariable = this.parser.getExpressionParser().parseNewVariableName();

stream.expect(Token.Type.NAME, "in");

// get the iterable variable
Expression<?> iterable = this.parser.getExpressionParser().parseExpression();

stream.expect(Token.Type.EXECUTE_END);

BodyNode body = this.parser.subparse((test) -> test.test(Token.Type.NAME, "endLazyFor"));

// skip the 'endLazyFor' token
stream.next();

stream.expect(Token.Type.EXECUTE_END);

return new ForNode(lineNumber, iterationVariable, iterable, body);
}

private static final class ForNode extends AbstractRenderableNode {

private final String variableName;
private final Expression<?> iterableExpression;
private final BodyNode body;

public ForNode(int lineNumber, String variableName, Expression<?> iterableExpression, BodyNode body) {
super(lineNumber);
this.variableName = variableName;
this.iterableExpression = iterableExpression;
this.body = body;
}

@Override
public void render(PebbleTemplateImpl self, Writer writer, EvaluationContext context) throws PebbleException, IOException {
Object value = iterableExpression.evaluate(self, context);
if (value == null) {
return;
}

Stream<?> stream = getStream(value);

context.pushScope();
stream.forEach((obj) -> {
try {
context.put(variableName, obj);
body.render(self, writer, context);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
context.popScope();
}

private Stream<?> getStream(Object obj) {
if (obj instanceof Stream) {
return (Stream<?>) obj;
} else if (obj instanceof Collection) {
return ((Collection<?>) obj).stream();
} else if (obj.getClass().isArray()) {
return Arrays.stream((Object[]) obj);
} else {
throw new ClassCastException(obj + " cannot be cast to Stream");
}
}

@Override
public void accept(NodeVisitor visitor) {
visitor.visit(this);
}

}

@Override
public String getTag() {
return "lazyFor";
}

}
Loading

0 comments on commit 0368a80

Please sign in to comment.