001 //$HeadURL: svn+ssh://melmasry@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/portal/standard/context/control/FullScreenListener.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.awt.Rectangle;
040 import java.io.IOException;
041 import java.net.MalformedURLException;
042 import java.util.HashMap;
043 import java.util.Iterator;
044 import java.util.LinkedList;
045 import java.util.List;
046 import java.util.Map;
047
048 import javax.servlet.http.HttpServletRequest;
049 import javax.servlet.http.HttpSession;
050 import javax.xml.parsers.ParserConfigurationException;
051 import javax.xml.transform.TransformerException;
052
053 import org.deegree.enterprise.control.FormEvent;
054 import org.deegree.enterprise.control.RPCMember;
055 import org.deegree.enterprise.control.RPCStruct;
056 import org.deegree.enterprise.control.RPCWebEvent;
057 import org.deegree.framework.log.ILogger;
058 import org.deegree.framework.log.LoggerFactory;
059 import org.deegree.framework.util.MapUtils;
060 import org.deegree.framework.util.Parameter;
061 import org.deegree.framework.xml.XMLFragment;
062 import org.deegree.i18n.Messages;
063 import org.deegree.model.crs.CoordinateSystem;
064 import org.deegree.model.spatialschema.Envelope;
065 import org.deegree.model.spatialschema.GeometryFactory;
066 import org.deegree.model.spatialschema.Point;
067 import org.deegree.portal.Constants;
068 import org.deegree.portal.PortalException;
069 import org.deegree.portal.context.ContextException;
070 import org.deegree.portal.context.Frontend;
071 import org.deegree.portal.context.GUIArea;
072 import org.deegree.portal.context.General;
073 import org.deegree.portal.context.GeneralExtension;
074 import org.deegree.portal.context.Module;
075 import org.deegree.portal.context.ViewContext;
076 import org.deegree.portal.context.XMLFactory;
077 import org.xml.sax.SAXException;
078
079 /**
080 * Convert the current view context to a full screen mode. It hides all the modules except the map
081 * and the toolbar. It also keeps whatever changes were made in the original context to the full
082 * screen context
083 *
084 * @author <a href="mailto:elmasry@lat-lon.de">Moataz Elmasry</a>
085 * @author last edited by: $Author: $
086 *
087 * @version $Revision: $, $Date: 1 Jun 2007 10:12:29$
088 */
089 public class FullScreenListener extends AbstractContextListener {
090
091 private int width = 0;
092
093 private Map<String, String> modulesMap = null;
094
095 /**
096 * the path to where the Web Map Context files are found
097 */
098 public static final String CONTEXTPATH = "WEB-INF/conf/igeoportal";
099
100 private String xslFileName = null;
101
102 private HttpSession session = null;
103
104 /**
105 * A <code>String</code> defining the name of the xsl file that defines the transformation
106 * from a context to html. This must be placed, together with the map context xml and helper xsl
107 * files, under <code>${context-home}/WEB-INF/conf/igeoportal/</code>.
108 */
109 protected static final String DEFAULT_CTXT2HTML = "WEB-INF/conf/igeoportal/context2HTML.xsl";
110
111 private static final ILogger LOG = LoggerFactory.getLogger( ResetContextListener.class );
112
113 private static final String DISPLAYED_MODULES = "DISPLAYED_MODULES";
114
115 private static final String NORMALSCREEN_MAPCONTEXT = "NormalScreenMapContext";
116
117 /*
118 * (non-Javadoc)
119 *
120 * @see org.deegree.enterprise.control.WebListener#actionPerformed(org.deegree.enterprise.control.FormEvent)
121 */
122 @Override
123 public void actionPerformed( FormEvent event ) {
124
125 RPCWebEvent rpc = (RPCWebEvent) event;
126
127 try {
128 validate( rpc );
129 validateCntxtProperties();
130 initialize();
131 } catch ( PortalException e ) {
132 LOG.logError( e.getMessage(), e );
133 e.printStackTrace();
134 gotoErrorPage( e.getMessage() );
135 return;
136 }
137
138 try {
139 ViewContext fullScreenContext = setToFullScreen( rpc );
140 setCurrentContext( fullScreenContext );
141 } catch ( Exception e ) {
142 LOG.logError( e.getMessage(), e );
143 e.printStackTrace();
144 gotoErrorPage( e.getMessage() );
145 return;
146 }
147 }
148
149 /**
150 * ValidateRPC looks in the RPCStruct for all needed elements and gotoErrorPage in case an
151 * element is found or wronglz formated, this is useful so that we won't need to check later for
152 * anz variables, simply get them and start Working
153 *
154 * @param rpc
155 * @throws PortalException
156 */
157 protected void validate( RPCWebEvent rpc )
158 throws PortalException {
159
160 RPCStruct struct = extractRPCStruct( rpc, 0 );
161
162 RPCMember layerListRPC = struct.getMember( "layerList" );
163 validateLayerList( layerListRPC );
164
165 RPCMember bboxRPC = struct.getMember( "boundingBox" );
166 validateBBox( bboxRPC );
167 }
168
169 /**
170 * This method checks the context.properties file to make sure that all fields needed are
171 * available
172 *
173 */
174 protected void validateCntxtProperties()
175 throws PortalException {
176
177 String displayedModules = ContextMessages.getString( DISPLAYED_MODULES );
178 if ( displayedModules == null ) {
179 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
180 ContextMessages.getName(), "DISPLAYED_MODULES" ) );
181 }
182
183 if ( displayedModules.indexOf( "MANDATORY_MODULE_MAP" ) < 0 ) {
184 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
185 ContextMessages.getName(), "MANDATORY_MODULE_MAP" ) );
186 }
187
188 if ( displayedModules.indexOf( "MANDATORY_MODULE_TOOLBAR" ) < 0 ) {
189 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
190 ContextMessages.getName(), "MANDATORY_MODULE_TOOLBAR" ) );
191 }
192
193 String mapName = ContextMessages.getString( "MANDATORY_MODULE_MAP" );
194 if ( mapName == null ) {
195 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MAND_PARAM",
196 ContextMessages.getName(), "MANDATORY_MODULE_MAP" ) );
197 }
198
199 String toolbarName = ContextMessages.getString( "MANDATORY_MODULE_TOOLBAR" );
200 if ( toolbarName == null ) {
201 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MAND_PARAM",
202 ContextMessages.getName(), "MANDATORY_MODULE_TOOLBAR" ) );
203 }
204
205 int width = Integer.parseInt( ContextMessages.getString( "MAP_WIDTH" ) );
206 if ( width <= 0 ) {
207 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
208 ContextMessages.getName(), "MAP_WIDTH" ) );
209 }
210
211 String normalScreen = ContextMessages.getString( "NORMAL_SIZE_SCREEN" );
212 if ( normalScreen == null ) {
213 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE",
214 ContextMessages.getName(), "NORMAL_SIZE_SCREEN" ) );
215 }
216 }
217
218 /**
219 * Initializes the global variables
220 *
221 * @throws PortalException
222 */
223 protected void initialize()
224 throws PortalException {
225
226 try {
227 xslFileName = "file://" + getHomePath() + DEFAULT_CTXT2HTML;
228
229 width = Integer.parseInt( ContextMessages.getString( "MAP_WIDTH" ) );
230 session = ( (HttpServletRequest) this.getRequest() ).getSession();
231
232 modulesMap = loadModulesNames( DISPLAYED_MODULES );
233 } catch ( Exception e ) {
234 LOG.logError( e.getMessage() );
235 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_INITIALIZE", e ) );
236 }
237 }
238
239 /**
240 * Applies the modules read from the context.properties file to the current context using the
241 * data from the session on the defaultContext
242 *
243 * @param rpc
244 * @return the view context for full screen
245 * @throws ParserConfigurationException
246 * @throws PortalException
247 * @throws ContextException
248 */
249 protected ViewContext setToFullScreen( RPCWebEvent rpc )
250 throws ParserConfigurationException, PortalException, ContextException {
251
252 RPCStruct struct = extractRPCStruct( rpc, 0 );
253 ViewContext tempContext = applyLayers( struct );
254
255 try {
256 XMLFragment xmlActualContext = XMLFactory.export( tempContext );
257 // Saving the original Context
258 session.setAttribute( NORMALSCREEN_MAPCONTEXT, xmlActualContext );
259 } catch ( ParserConfigurationException e ) {
260 LOG.logError( e.getMessage() );
261 throw new ParserConfigurationException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_TRANSFORM" ) );
262 }
263 return createFullScreenContext( struct, tempContext );
264 }
265
266 /**
267 * Takes in viewContext converts it to a html of the viewcontext and display it
268 *
269 * @param vc the Viewcontext after convert
270 * @throws ParserConfigurationException
271 * @throws TransformerException
272 * @throws SAXException
273 * @throws MalformedURLException
274 * @throws IOException
275 */
276 protected void setCurrentContext( ViewContext vc )
277 throws ParserConfigurationException, TransformerException, SAXException,
278 MalformedURLException, IOException {
279
280 try {
281 XMLFragment xml = XMLFactory.export( vc );
282 String newHtml = transformToHtmlMapContext( xml, xslFileName );
283 session.setAttribute( ContextSwitchListener.NEW_CONTEXT_HTML, newHtml );
284 } catch ( ParserConfigurationException e ) {
285 LOG.logError( e.getMessage() );
286 throw new ParserConfigurationException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_TRANSFORM" ) );
287 }
288 }
289
290 /**
291 * Gets the current map context from the session and applies the current layers to it.
292 *
293 * @param struct
294 * @return the viewContext after applying the current layers to it
295 * @throws PortalException
296 */
297 private ViewContext applyLayers( RPCStruct struct )
298 throws PortalException {
299
300 ViewContext tempContext = null;
301 try {
302 String sessionId = (String) session.getAttribute( "SESSIONID" );
303 ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT );
304 tempContext = vc.clone( null, sessionId );
305
306 // Applying the layer setting to the current context
307 RPCMember[] layerList = ( (RPCStruct) struct.getMember( "layerList" ).getValue() ).getMembers();
308 changeLayerList( tempContext, layerList );
309
310 } catch ( PortalException e ) {
311 // throw new PortalException( Messages.getMessage(
312 // "IGEO_STD_CNTXT_ERROR_EMPTY_LAYERLIST" ) );
313 throw e;
314 } catch ( Exception e ) {
315 LOG.logError( e.getMessage() );
316 throw new PortalException( Messages.getMessage( "IGEO_STD_ERROR_UNKNOWN", e ) );
317 }
318 return tempContext;
319 }
320
321 /**
322 * Validates the data in the struct to make sure it contains a valid layerList
323 *
324 * @param layerListRPCMember
325 * @throws PortalException
326 */
327 protected void validateLayerList( RPCMember layerListRPCMember )
328 throws PortalException {
329
330 if ( layerListRPCMember == null || layerListRPCMember.getValue() == null ) {
331 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_RPC_MEMBER", "layerList" ) );
332 }
333
334 RPCMember[] layerList = null;
335 try {
336 layerList = ( (RPCStruct) layerListRPCMember.getValue() ).getMembers();
337 } catch ( Exception e ) {
338 LOG.logError( e.getMessage() );
339 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_WRONG_RPC_MEMBER_VALUE", "layerList" ) );
340 }
341
342 if ( layerList == null || layerList.length < 1 ) {
343 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_EMPTY_LAYERLIST", "layerList" ) );
344 }
345 }
346
347 /**
348 * Validates the data in the struct to make sure it contains a valid bbox
349 *
350 * @param bboxRPCMember
351 * @throws PortalException
352 */
353 protected void validateBBox( RPCMember bboxRPCMember )
354 throws PortalException {
355
356 if ( bboxRPCMember == null || bboxRPCMember.getValue() == null ) {
357 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_RPC_MEMBER", "boundingBox" ) );
358 }
359
360 RPCStruct bboxStruct = (RPCStruct) bboxRPCMember.getValue();
361 Double minx = null;
362 Double miny = null;
363 Double maxx = null;
364 Double maxy = null;
365
366 RPCMember mem = bboxStruct.getMember( Constants.RPC_BBOXMINX );
367 if ( mem != null ) {
368 minx = (Double) mem.getValue();
369 }
370 mem = bboxStruct.getMember( Constants.RPC_BBOXMINY );
371 if ( mem != null ) {
372 miny = (Double) mem.getValue();
373 }
374 mem = bboxStruct.getMember( Constants.RPC_BBOXMAXX );
375 if ( mem != null ) {
376 maxx = (Double) mem.getValue();
377 }
378 mem = bboxStruct.getMember( Constants.RPC_BBOXMAXY );
379 if ( mem != null ) {
380 maxy = (Double) mem.getValue();
381 }
382
383 if ( minx == null || maxx == null || miny == null || maxy == null ) {
384 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_WRONG_RPC_MEMBER_VALUE", "boundingBox" ) );
385 }
386 if ( minx >= maxx || miny >= maxy ) {
387 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_BBOX_BOUNDARIES" ) );
388 }
389 }
390
391 /**
392 * Extracts shown modules names from the context.properties file
393 *
394 * @param selectedModules
395 * The modules names key as written in the context.properties file
396 * @return Map contains all the used modules
397 */
398 private Map<String, String> loadModulesNames( String selectedModules ) {
399
400 String modulesNames = ContextMessages.getString( selectedModules );
401 Map<String, String> modules = new HashMap<String, String>();
402 String[] tmpNames = modulesNames.split( ";" );
403 for ( int i = 0; i < tmpNames.length; i++ ) {
404 String value = ContextMessages.getString( tmpNames[i] );
405 if ( tmpNames[i] != null && value != null ) {
406 modules.put( tmpNames[i], value );
407 }
408 }
409 return modules;
410 }
411
412 /**
413 * Sets the given context to FullScreen mode.
414 *
415 * @param struct the rpc struct containing the current bbox envelope
416 * @param vc view context with the layers
417 * @return The context transformed to the fullScreen size
418 * @throws ContextException
419 * @throws PortalException
420 */
421 protected ViewContext createFullScreenContext( RPCStruct struct, ViewContext vc )
422 throws ContextException, PortalException {
423
424 RPCStruct bBoxStruct = (RPCStruct) struct.getMember( "boundingBox" ).getValue();
425 Envelope envelope = extractBBox( bBoxStruct, null );
426
427 String sessionID = (String) session.getAttribute( "SESSIONID" );
428 ViewContext fullscreenContext = null;
429 try {
430 fullscreenContext = vc.clone( null, sessionID );
431 } catch ( Exception e ) {
432 throw new ContextException( "The view context couldn't be cloned" );
433 }
434 General general = fullscreenContext.getGeneral();
435 GeneralExtension extension = general.getExtension();
436 Frontend frontEnd = extension.getFrontend();
437
438 // The bbox values are changed here
439 Point[] points = general.getBoundingBox();
440 // if there are no 2 points, then nothing happens
441 if ( points.length == 2 ) {
442 Rectangle rect = general.getWindow();
443 rect.width = width; // setting new window width
444 CoordinateSystem crs = points[0].getCoordinateSystem();
445 Envelope bbox = MapUtils.ensureAspectRatio( envelope, rect.width, rect.height );
446
447 Point[] newPoints = new Point[2];
448 newPoints[0] = GeometryFactory.createPoint( bbox.getMin(), crs );
449 newPoints[1] = GeometryFactory.createPoint( bbox.getMax(), crs );
450
451 general.setBoundingBox( newPoints );
452 } else {
453 throw new ContextException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_VIEWCONTEXT", "bounding box" ) );
454 }
455
456 // Here removing all the side modules
457 List<GUIArea> contextAreas = new LinkedList<GUIArea>();
458 // Makign sure we fetched the names right, otherwise we don't have the names to compare with
459
460 // Adding GuiAreas to a list to do a for loop
461 // instead of accessing them individually
462 GUIArea curArea = null;
463 if ( ( curArea = frontEnd.getNorth() ) != null ) {
464 contextAreas.add( curArea );
465 }
466 if ( ( curArea = frontEnd.getSouth() ) != null ) {
467 contextAreas.add( curArea );
468 }
469 if ( ( curArea = frontEnd.getEast() ) != null ) {
470 contextAreas.add( curArea );
471 }
472 if ( ( curArea = frontEnd.getWest() ) != null ) {
473 contextAreas.add( curArea );
474 }
475 if ( ( curArea = frontEnd.getCenter() ) != null ) {
476 contextAreas.add( curArea );
477 }
478
479 Iterator<GUIArea> it = contextAreas.iterator();
480
481 // We now know for sure, that will find the map and the toolbar
482 // since we already called validateCntxtProperties()
483 boolean mapFound = false;
484 boolean toolbarFound = false;
485 while ( it.hasNext() ) {
486 GUIArea area = it.next();
487 boolean found = false;
488
489 Module[] modules = area.getModules();
490 for ( int i = 0; i < modules.length; i++ ) {
491 // If the module name was in the list of shownModules then keep it
492 if ( modulesMap.containsValue( modules[i].getName() ) ) {
493 found = true;
494 if ( modules[i].getName().compareTo( modulesMap.get( "MANDATORY_MODULE_MAP" ) ) == 0 ) {
495 // The map view or the tool bar has been found
496 modules[i].setWidth( width );
497 mapFound = true;
498 }
499
500 if ( modules[i].getName().compareTo( modulesMap.get( "MANDATORY_MODULE_TOOLBAR" ) ) == 0 ) {
501 modules[i].setWidth( width );
502 toolbarFound = true;
503 }
504 continue;
505 }
506 modules[i].setHidden( true );
507 }
508 if ( !found ) {
509 area.setArea( 0 );
510 area.setHidden( true );
511 }
512 }
513
514 if ( !mapFound ) {
515 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MODULE",
516 modulesMap.get( "MANDATORY_MODULE_MAP" ) ) );
517 }
518 if ( !toolbarFound ) {
519 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MODULE",
520 modulesMap.get( "MANDATORY_MODULE_TOOLBAR" ) ) );
521 }
522
523 // Changing the full screen button to normal size screen button
524 Module toolBar = frontEnd.getCenter().getModule( "Toolbar" );
525 if ( toolBar != null ) {
526 String[] removedBtns = ContextMessages.getString( "REMOVED_BUTTONS" ).split( ";" );
527
528 // Remove only the parameters that exist in the hash map
529 String[] names = toolBar.getParameter().getParameterNames();
530 for ( int i = 0; i < names.length; i++ ) {
531 for ( int j = 0; j < removedBtns.length; j++ ) {
532 if ( names[i].indexOf( removedBtns[j] ) >= 0 ) {
533 toolBar.getParameter().removeParameter( names[i] );
534 }
535 }
536 }
537 }
538
539 Parameter param = new Parameter( ContextMessages.getString( "NORMAL_SIZE_SCREEN" ), "PushButton" );
540 toolBar.addParameter( param );
541
542 return fullscreenContext;
543 }
544 }