package org.jboss.seam.navigation; import static org.jboss.seam.annotations.Install.BUILT_IN; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.faces.context.FacesContext; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.contexts.Contexts; /** * Maintains a set of "safe" actions that may be performed * by <s:link/>, as determined by actually parsing * the view. * * @author Gavin King * */ @Scope(ScopeType.APPLICATION) @BypassInterceptors @Name("org.jboss.seam.navigation.safeActions") @Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext") public class SafeActions { private Set<String> safeActions = Collections.synchronizedSet( new HashSet<String>() ); public static String toActionId(String viewId, String expression) { return viewId.substring(1) + ':' + expression.substring( 2, expression.length()-1 ); } public static String toAction(String id) { int loc = id.indexOf(':'); if (loc<0) throw new IllegalArgumentException(); return "#{" + id.substring(loc+1) + "}"; } public void addSafeAction(String id) { safeActions.add(id); } public boolean isActionSafe(String id) { if ( safeActions.contains(id) ) return true; int loc = id.indexOf(':'); if (loc<0) throw new IllegalArgumentException("Invalid action method " + id); String viewId = id.substring(0, loc); String action = "\"#{" + id.substring(loc+1) + "}\""; InputStream is = FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(viewId); if (is==null) throw new IllegalStateException("Unable to read view " + "/" + viewId + " to execute action " + action); BufferedReader reader = new BufferedReader( new InputStreamReader(is) ); try { while ( reader.ready() ) { if ( reader.readLine().contains(action) ) { addSafeAction(id); return true; } } return false; } catch (IOException ioe) { throw new RuntimeException("Error parsing view " + "/" + viewId + " to execute action " + action, ioe); } finally { try { reader.close(); } catch (IOException ioe) { throw new RuntimeException(ioe); } } } public static SafeActions instance() { if ( !Contexts.isApplicationContextActive() ) { throw new IllegalStateException("No active application context"); } return (SafeActions) Component.getInstance(SafeActions.class, ScopeType.APPLICATION); } }