001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/portal/standard/context/control/ContextSaveListener.java $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 - Department of Geography, University of Bonn
006 and
007 - lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036
037 package org.deegree.portal.standard.context.control;
038
039 import java.io.File;
040 import java.io.FileOutputStream;
041 import java.io.OutputStream;
042
043 import javax.servlet.http.HttpServletRequest;
044 import javax.servlet.http.HttpSession;
045 import javax.xml.transform.Source;
046 import javax.xml.transform.Transformer;
047 import javax.xml.transform.TransformerFactory;
048 import javax.xml.transform.dom.DOMSource;
049 import javax.xml.transform.stream.StreamResult;
050
051 import org.deegree.enterprise.control.FormEvent;
052 import org.deegree.enterprise.control.RPCMember;
053 import org.deegree.enterprise.control.RPCMethodCall;
054 import org.deegree.enterprise.control.RPCParameter;
055 import org.deegree.enterprise.control.RPCStruct;
056 import org.deegree.enterprise.control.RPCUtils;
057 import org.deegree.enterprise.control.RPCWebEvent;
058 import org.deegree.framework.log.ILogger;
059 import org.deegree.framework.log.LoggerFactory;
060 import org.deegree.framework.util.StringTools;
061 import org.deegree.framework.xml.XMLFragment;
062 import org.deegree.i18n.Messages;
063 import org.deegree.model.spatialschema.Envelope;
064 import org.deegree.portal.Constants;
065 import org.deegree.portal.PortalException;
066 import org.deegree.portal.context.ViewContext;
067 import org.deegree.portal.context.XMLFactory;
068 import org.w3c.dom.Document;
069
070 /**
071 * This class saves a new context based on changes made by the user (on the client) and based on the original context
072 * xml. <br/>
073 * Files are saved under .../WEB-INF/xml/users/some_user, where some_user is passed as an RPC parameter. Files should be
074 * saved with .xml extension because the default load context listener class looks up those files. <br/>
075 *
076 * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a>
077 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
078 * @author last edited by: $Author: jmays $
079 *
080 * @version $Revision: 21347 $, $Date: 2009-12-09 17:04:39 +0100 (Mi, 09. Dez 2009) $
081 */
082 public class ContextSaveListener extends AbstractContextListener {
083
084 private static final ILogger LOG = LoggerFactory.getLogger( ContextSaveListener.class );
085
086 private static String userDir = "WEB-INF/conf/igeoportal/users/";
087
088 private static String contextDir = "WEB-INF/conf/igeoportal/";
089
090 /*
091 * (non-Javadoc)
092 *
093 * @see org.deegree.enterprise.control.WebListener#actionPerformed(org.deegree.enterprise.control.FormEvent)
094 */
095 @Override
096 public void actionPerformed( FormEvent event ) {
097
098 RPCWebEvent rpc = (RPCWebEvent) event;
099 try {
100 validate( rpc );
101 } catch ( PortalException e ) {
102 LOG.logError( e.getMessage(), e );
103 gotoErrorPage( Messages.getMessage( "IGEO_STD_CNTXT_INVALID_RPC", "ContextSave", e.getMessage() ) );
104 return;
105 }
106
107 String newContext = null;
108 try {
109 newContext = storeContext( rpc );
110 } catch ( Exception e ) {
111 LOG.logError( e.getMessage(), e );
112 gotoErrorPage( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_SAVE_CNTXT" ) );
113 return;
114 }
115
116 // forward to new page
117 this.getRequest().setAttribute( Constants.MESSAGE,
118 Messages.getMessage( "IGEO_STD_CNTXT_SUCCESS_SAVE_CNTXT", newContext ) );
119 }
120
121 /**
122 * stores the current context of the user with a defined name
123 *
124 * @param event
125 * @return name of the context that has been stored
126 * @throws PortalException
127 */
128 private String storeContext( RPCWebEvent event )
129 throws PortalException {
130
131 RPCMethodCall mc = event.getRPCMethodCall();
132 RPCParameter[] pars = mc.getParameters();
133 RPCStruct struct = (RPCStruct) pars[0].getValue();
134
135 // read base context
136 StringBuffer path2Dir = new StringBuffer( getHomePath() );
137 path2Dir.append( contextDir );
138
139 // access base context
140 HttpSession session = ( (HttpServletRequest) getRequest() ).getSession();
141 ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT );
142 // change values: BBOX and Layer List
143 Envelope bbox = extractBBox( (RPCStruct) struct.getMember( Constants.RPC_BBOX ).getValue(), null );
144 changeBBox( vc, bbox );
145 RPCMember[] layerList = ( (RPCStruct) struct.getMember( "layerList" ).getValue() ).getMembers();
146 changeLayerList( vc, layerList );
147
148 // save new context
149 // get map context value
150 String username = "default";
151 try {
152 String sid = RPCUtils.getRpcPropertyAsString( struct, "sessionID" );
153 LOG.logDebug( "sessionID ", sid );
154 username = getUserName( sid );
155 if ( username == null ) {
156 username = "default";
157 }
158 LOG.logDebug( "username ", username );
159 } catch ( Exception e ) {
160 LOG.logError( e.getMessage(), e );
161 }
162
163 String newContext = RPCUtils.getRpcPropertyAsString( struct, "newContext" );
164
165 // check for init params, adjusting the file name input of the user
166 if ( getInitParameter( "RESTRICT_CHARS" ) != null || getInitParameter( "ADD_XML_SUFFIX" ) != null ) {
167 newContext = fixFileName( newContext, getInitParameter( "RESTRICT_CHARS" ),
168 getInitParameter( "ADD_XML_SUFFIX" ) );
169 }
170
171 path2Dir = new StringBuffer( getHomePath() );
172 path2Dir.append( userDir );
173 path2Dir.append( username );
174 File file = new File( path2Dir.toString() );
175 if ( !file.exists() ) {
176 // create directory if not exists
177 file.mkdir();
178 }
179 path2Dir.append( "/" );
180 path2Dir.append( newContext );
181
182 saveDocument( vc, path2Dir.toString() );
183
184 return newContext;
185 }
186
187 /**
188 * This method replaces all forbidden characters with underscores ("_") and sets the file extension to ".xml".
189 * Accepted characters are: [a-zA-Z_0-9-.]
190 *
191 * @param newContext
192 * @param restrictedChars
193 * may be null
194 * @param addXmlSuffix
195 * may be null
196 * @return updated version of the passed String
197 */
198 private String fixFileName( String newContext, String restrictedChars, String addXmlSuffix ) {
199
200 if ( restrictedChars != null ) {
201 String regex = null;
202 if ( restrictedChars.length() == 0 ) {
203 // replace everything that is not a word character [a-zA-Z_0-9]
204 regex = "[^\\w]";
205 } else {
206 // replace everything that is not a word character [a-zA-Z_0-9] or one of the restrictedChars
207 regex = "[^\\w" + restrictedChars + "]";
208 }
209
210 // replace forbidden characters with underscore
211 newContext = newContext.replaceAll( regex, "_" );
212 // trimm double underscores
213 while ( newContext.contains( "__" ) ) {
214 newContext = newContext.replace( "__", "_" );
215 }
216 }
217
218 if ( "true".equals( addXmlSuffix ) ) {
219 // add proper file ending ".xml"
220 if ( !newContext.endsWith( ".xml" ) ) {
221 newContext += ".xml";
222 }
223 }
224 return newContext;
225 }
226
227 /**
228 * saves the new context as xml
229 *
230 * @param vc
231 * @param filename
232 * @throws PortalException
233 */
234 public static final void saveDocument( ViewContext vc, String filename )
235 throws PortalException {
236 try {
237 XMLFragment xml = XMLFactory.export( vc );
238 FileOutputStream fos = new FileOutputStream( filename );
239 xml.write( fos );
240 fos.close();
241 } catch ( Exception e ) {
242 LOG.logError( e.getMessage(), e );
243 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_SAVE_FILE", filename ) );
244 }
245 }
246
247 /**
248 * validates the incoming RPC event
249 *
250 * @param rpc
251 * @throws PortalException
252 */
253 private void validate( RPCWebEvent rpc )
254 throws PortalException {
255 RPCMethodCall mc = rpc.getRPCMethodCall();
256 RPCParameter param = mc.getParameters()[0];
257 RPCStruct struct = (RPCStruct) param.getValue();
258 RPCMember username = struct.getMember( "sessionID" );
259 if ( username == null ) {
260 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_PARAM", "sessionID", "ContextSave" ) );
261 }
262 RPCMember newContext = struct.getMember( "newContext" );
263 if ( newContext == null ) {
264 throw new PortalException(
265 Messages.getMessage( "IGEO_STD_CNTXT_MISSING_PARAM", "newContext", "ContextSave" ) );
266 }
267 RPCMember layerList = struct.getMember( "layerList" );
268 if ( layerList == null ) {
269 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_PARAM", "layerList", "ContextSave" ) );
270 }
271 // TODO validate box: should do this in a common (static) method
272 // for many listeners that need a bbox
273 }
274
275 /**
276 * common method to save xml
277 *
278 * @param os
279 * @param doc
280 * @throws PortalException
281 */
282 protected static void internalSave( OutputStream os, Document doc )
283 throws PortalException {
284 try {
285 Source source = new DOMSource( doc );
286 Transformer transformer = TransformerFactory.newInstance().newTransformer();
287 transformer.transform( source, new StreamResult( os ) );
288 } catch ( Exception e ) {
289 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_INTERNAL_SAVE",
290 StringTools.stackTraceToString( e.getStackTrace() ) ) );
291 }
292 }
293
294 }