/** * Copyright 2005-2010 hdiv.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.hdiv.state; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hdiv.exception.HDIVException; import org.hdiv.util.EncodingUtil; import org.hdiv.util.HDIVErrorCodes; /** * Class containing utility methods for state. * * @author Roberto Velasco */ public class StateUtil { /** * Commons Logging instance. */ private Log log = LogFactory.getLog(StateUtil.class); /** * Memory strategy name */ private static final String MEMORY_STRATEGY = "memory"; /** * Cipher strategy name */ private static final String CIPHER_STRATEGY = "cipher"; /** * Hash strategy name */ private static final String HASH_STRATEGY = "hash"; /** * Pattern to check if the memory strategy is being used */ private static final String MEMORY_PATTERN = "([0-9]+-){2}[A-Za-z0-9]+"; /** * Compiled MEMORY_PATTERN */ private Pattern memoryPattern = Pattern.compile(MEMORY_PATTERN); /** * Parameter name included by HDIV in the requests or forms which will contain * the state identifier, in the memory strategy, or the state itself, in the * encoded and hash strategies. */ private String HDIVParameter; /** * Utility methods for encoding */ private EncodingUtil encodingUtil; /** * User defined strategy by spring factory */ private String strategy; /** * StateUtil initialization with HDIV parameter name stored in http session. */ public void init() { } /** * Restore state data from <code>request</code>. State restore from memory can * be done using an identifier or or using the serialized data received in the * request. * * @param requestState String that contains HDIV state received in the request * @return State Restore state data from <code>request</code>. * @throws HDIVException If the state doesn't exist a new HDIV exception is * thrown. */ public IState restoreState(String requestState) { IState restoredState = null; if (this.isMemoryStrategy(requestState)) { restoredState = this.getStateFromSession(requestState); } else if (this.isCipherStrategy()) { restoredState = (IState) encodingUtil.decode64Cipher(requestState); } else if (this.isHashStrategy()) { restoredState = this.restoreHashState(requestState); } if (restoredState == null) { throw new HDIVException(HDIVErrorCodes.HDIV_PARAMETER_INCORRECT_VALUE); } return restoredState; } /** * Checks if the memory strategy is being used * * @return True if strategy is memory. False in otherwise. */ public boolean isMemoryStrategy(String value) { Matcher m = this.memoryPattern.matcher(value); return (m.matches() ? true : this.strategy.equalsIgnoreCase(MEMORY_STRATEGY)); } /** * Checks if the cipher (encoded) strategy is being used. * * @return True if strategy is cipher. False in otherwise. */ private boolean isCipherStrategy() { return this.strategy.equalsIgnoreCase(CIPHER_STRATEGY); } /** * Checks if the hash strategy is being used. * * @return True if strategy is hash. False in otherwise. */ private boolean isHashStrategy() { return this.strategy.equalsIgnoreCase(HASH_STRATEGY); } /** * Restores the state using the identifier obtained from the * <code>HDIVParameter</code> of the request. * * @param value <code>HDIVParameter</code> parameter value. * @return State with all the page data. */ private IState getStateFromSession(String value) { int firstSeparator = value.indexOf("-"); int lastSeparator = value.lastIndexOf("-"); if ((firstSeparator == -1) || (lastSeparator == -1)) { throw new HDIVException(HDIVErrorCodes.HDIV_PARAMETER_INCORRECT_VALUE); } String page = value.substring(0, firstSeparator); String stateId = value.substring(firstSeparator + 1, lastSeparator); IState sessionState = this.encodingUtil.getSession().getState(page, stateId); if (sessionState == null) { throw new HDIVException(HDIVErrorCodes.HDIV_PARAMETER_INCORRECT_VALUE); } return sessionState; } /** * Checks if the state hash received from the client and the hash stored in * session match. If it is true, an object of type <code>IState</code> is * returned. Otherwise, a HDIVException is thrown. * * @param value State received in the request encoded in Base64 * @return Decoded state of type <code>IState</code> obtained from * <code>value</code> */ public IState restoreHashState(String value) { String restoredStateHash = this.encodingUtil.calculateStateHash(value); IState decodedState = (IState) encodingUtil.decode64(value); String sessionStateHash = this.encodingUtil.getSession().getStateHash(decodedState.getPageId(), decodedState.getId()); if (restoredStateHash.equals(sessionStateHash)) { return decodedState; } return null; } /** * @return Returns the HDIV state parameter. */ public String getHDIVParameter() { return HDIVParameter; } /** * @param parameter The hDIVParameter to set. */ public void setHDIVParameter(String parameter) { HDIVParameter = parameter; } /** * @return Returns the encoding util. */ public EncodingUtil getEncodingUtil() { return encodingUtil; } /** * @param encodingUtil The encodingUtil to set. */ public void setEncodingUtil(EncodingUtil encodingUtil) { this.encodingUtil = encodingUtil; } /** * @param strategy The strategy to set. */ public void setStrategy(String strategy) { this.strategy = strategy; } }