001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/portal/common/control/AbstractSimplePrintListener.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    package org.deegree.portal.common.control;
037    
038    import java.awt.Color;
039    import java.awt.Graphics;
040    import java.awt.Image;
041    import java.awt.image.BufferedImage;
042    import java.io.File;
043    import java.io.FileOutputStream;
044    import java.io.IOException;
045    import java.io.RandomAccessFile;
046    import java.net.URI;
047    import java.net.URL;
048    import java.text.SimpleDateFormat;
049    import java.util.ArrayList;
050    import java.util.GregorianCalendar;
051    import java.util.HashMap;
052    import java.util.List;
053    import java.util.Locale;
054    import java.util.Map;
055    import java.util.UUID;
056    
057    import javax.servlet.ServletContext;
058    import javax.servlet.http.HttpServletRequest;
059    
060    import net.sf.jasperreports.engine.JRDataSource;
061    import net.sf.jasperreports.engine.JREmptyDataSource;
062    import net.sf.jasperreports.engine.JRException;
063    import net.sf.jasperreports.engine.JasperFillManager;
064    import net.sf.jasperreports.engine.JasperPrint;
065    import net.sf.jasperreports.engine.JasperPrintManager;
066    import net.sf.jasperreports.engine.JasperRunManager;
067    
068    import org.deegree.enterprise.control.AbstractListener;
069    import org.deegree.enterprise.control.FormEvent;
070    import org.deegree.enterprise.control.RPCMember;
071    import org.deegree.enterprise.control.RPCStruct;
072    import org.deegree.enterprise.control.RPCWebEvent;
073    import org.deegree.framework.log.ILogger;
074    import org.deegree.framework.log.LoggerFactory;
075    import org.deegree.framework.util.CharsetUtils;
076    import org.deegree.framework.util.ImageUtils;
077    import org.deegree.framework.util.KVP2Map;
078    import org.deegree.framework.util.MapUtils;
079    import org.deegree.framework.util.Pair;
080    import org.deegree.framework.util.StringTools;
081    import org.deegree.framework.xml.NamespaceContext;
082    import org.deegree.framework.xml.XMLFragment;
083    import org.deegree.framework.xml.XMLParsingException;
084    import org.deegree.framework.xml.XMLTools;
085    import org.deegree.model.spatialschema.Envelope;
086    import org.deegree.model.spatialschema.GeometryFactory;
087    import org.deegree.model.spatialschema.Point;
088    import org.deegree.ogcbase.CommonNamespaces;
089    import org.deegree.ogcwebservices.InconsistentRequestException;
090    import org.deegree.ogcwebservices.wms.operation.GetMap;
091    import org.deegree.portal.PortalException;
092    import org.deegree.portal.PortalUtils;
093    import org.deegree.portal.context.Layer;
094    import org.deegree.portal.context.Style;
095    import org.deegree.portal.context.ViewContext;
096    import org.deegree.security.drm.model.User;
097    import org.xml.sax.SAXException;
098    
099    /**
100     * performs a print request/event by creating a PDF document from the current map. For this JASPER is used. Well known
101     * parameters that can be passed to a jaser report are:<br>
102     * <ul>
103     * <li>MAP</li>
104     * <li>LEGEND</li>
105     * <li>DATE</li>
106     * <li>MAPSCALE</li>
107     * </ul>
108     * <br>
109     * Additionaly parameters named 'TA:XXXX' can be used. deegree will create a k-v-p for each TA:XXXX passed as part of
110     * RPC.
111     * 
112     * 
113     * @version $Revision: 28670 $
114     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
115     * @author last edited by: $Author: apoth $
116     * 
117     * @version $Revision: 28670 $, $Date: 2010-12-10 09:34:18 +0100 (Fr, 10 Dez 2010) $
118     */
119    public abstract class AbstractSimplePrintListener extends AbstractListener {
120    
121        private static ILogger LOG = LoggerFactory.getLogger( AbstractSimplePrintListener.class );
122    
123        private String defaultTemplateDir = "/WEB-INF/igeoportal/print";
124    
125        /**
126         * @param e
127         */
128        @Override
129        public void actionPerformed( FormEvent e ) {
130            RPCWebEvent rpc = (RPCWebEvent) e;
131            try {
132                validate( rpc );
133            } catch ( Exception ex ) {
134                LOG.logError( ex.getMessage(), ex );
135                gotoErrorPage( ex.getMessage() );
136            }
137    
138            ViewContext vc = getViewContext( rpc );
139            if ( vc == null ) {
140                LOG.logError( "no valid ViewContext available; maybe your session has reached timeout limit" ); //$NON-NLS-1$
141                gotoErrorPage( Messages.getString( "AbstractSimplePrintListener.MISSINGCONTEXT" ) );
142                setNextPage( "error.jsp" );
143                return;
144            }
145            try {
146                printMap( vc, rpc );
147            } catch ( Exception ex ) {
148                ex.printStackTrace();
149                LOG.logError( ex.getMessage(), ex );
150                gotoErrorPage( ex.getMessage() );
151            }
152        }
153    
154        /**
155         * 
156         * @param vc
157         * @param rpc
158         * @throws PortalException
159         * @throws IOException
160         * @throws SAXException
161         * @throws XMLParsingException
162         * @throws InconsistentRequestException
163         */
164        private void printMap( ViewContext vc, RPCWebEvent rpc )
165                                throws Exception {
166    
167            RPCStruct struct = (RPCStruct) rpc.getRPCMethodCall().getParameters()[1].getValue();
168            String printTemplate = (String) struct.getMember( "TEMPLATE" ).getValue();
169    
170            // read print template directory from defaultTemplateDir, or, if available, from the init
171            // parameters
172            String templateDir = getInitParameter( "TEMPLATE_DIR" );
173            if ( templateDir == null ) {
174                templateDir = defaultTemplateDir;
175            }
176            ServletContext sc = ( (HttpServletRequest) getRequest() ).getSession( true ).getServletContext();
177            String path = sc.getRealPath( templateDir ) + '/' + printTemplate + ".jasper";
178            String pathx = sc.getRealPath( templateDir ) + '/' + printTemplate + ".jrxml";
179            Pair<Integer, Integer> size = getMapTemplateSize( pathx );
180    
181            List<String> getMap = createGetMapRequests( vc, rpc, size );
182            String image = performGetMapRequests( getMap );
183    
184            String legend = accessLegend( createLegendURLs( vc ) );
185    
186            String format = (String) rpc.getRPCMethodCall().getParameters()[0].getValue();
187    
188            if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
189                LOG.logDebug( "The jasper template is read from: ", path );
190                LOG.logDebug( "The jrxml template is read from: ", pathx );
191            }
192    
193            Map<String, Object> parameter = new HashMap<String, Object>();
194            parameter.put( "MAP", image );
195            parameter.put( "LEGEND", legend );
196    
197            // enable
198            if ( getInitParameter( "LOGO_URL" ) != null ) {
199                String logoUrl = getHomePath() + getInitParameter( "LOGO_URL" );
200                if ( new File( logoUrl ).exists() ) {
201                    parameter.put( "LOGO_URL", logoUrl );
202                }
203            }
204    
205            parameter.put( "ROOT", getHomePath() );
206    
207            SimpleDateFormat sdf = new SimpleDateFormat( "dd.MM.yyyy", Locale.getDefault() );
208            // TODO deprecated - will be remove in future versions
209            parameter.put( "DATUM", sdf.format( new GregorianCalendar().getTime() ) );
210            // --------------------------------------------------------
211            parameter.put( "DATE", sdf.format( new GregorianCalendar().getTime() ) );
212    
213            double scale = calcScale( size, getMap.get( 0 ) );
214            parameter.put( "MAPSCALE", "" + Math.round( scale ) );
215            LOG.logDebug( "print map scale: ", scale );
216            // set text area values
217            RPCMember[] members = struct.getMembers();
218            for ( int i = 0; i < members.length; i++ ) {
219                if ( members[i].getName().startsWith( "TA:" ) ) {
220                    String s = members[i].getName().substring( 3, members[i].getName().length() );
221                    String val = (String) members[i].getValue();
222                    if ( val != null ) {
223                        val = new String( val.getBytes(), CharsetUtils.getSystemCharset() );
224                    }
225                    LOG.logDebug( "text area name: ", s );
226                    LOG.logDebug( "text area value: ", val );
227                    parameter.put( s, val );
228                }
229            }
230            System.out.println( parameter );
231            if ( "application/pdf".equals( format ) ) {
232    
233                // create the pdf
234                Object result = null;
235                try {
236                    JRDataSource ds = new JREmptyDataSource();
237                    result = JasperRunManager.runReportToPdf( path, parameter, ds );
238                } catch ( JRException e ) {
239                    LOG.logError( "Template: " + path );
240                    LOG.logError( e.getLocalizedMessage(), e );
241                    throw new PortalException( Messages.getString( "AbstractSimplePrintListener.REPORTCREATION" ) );
242                } finally {
243                    File file = new File( image );
244                    file.delete();
245                    file = new File( legend );
246                    file.delete();
247                }
248    
249                forwardPDF( result );
250    
251            } else if ( "image/png".equals( format ) ) {
252    
253                // create the image
254                Image result = null;
255                try {
256                    JRDataSource ds = new JREmptyDataSource();
257                    JasperPrint prt = JasperFillManager.fillReport( path, parameter, ds );
258                    result = JasperPrintManager.printPageToImage( prt, 0, 1 );
259                } catch ( JRException e ) {
260                    LOG.logError( e.getLocalizedMessage(), e );
261                    throw new PortalException( Messages.getString( "AbstractSimplePrintListener.REPORTCREATION" ) );
262                } finally {
263                    File file = new File( image );
264                    file.delete();
265                    file = new File( legend );
266                    file.delete();
267                }
268    
269                forwardImage( result, format );
270    
271            }
272        }
273    
274        private Pair<Integer, Integer> getMapTemplateSize( String path )
275                                throws Exception {
276            File file = new File( path );
277            XMLFragment xml = new XMLFragment( file.toURL() );
278    
279            String xpathW = "detail/band/image/reportElement[./@key = 'image-1']/@width";
280            String xpathH = "detail/band/image/reportElement[./@key = 'image-1']/@height";
281            NamespaceContext nsc = CommonNamespaces.getNamespaceContext();
282            int w = XMLTools.getNodeAsInt( xml.getRootElement(), xpathW, nsc, -1 );
283            int h = XMLTools.getNodeAsInt( xml.getRootElement(), xpathH, nsc, -1 );
284            if ( w < 0 ) {
285                nsc.addNamespace( "jasper", URI.create( "http://jasperreports.sourceforge.net/jasperreports" ) );
286                xpathW = "jasper:detail/jasper:band/jasper:image/jasper:reportElement[./@key = 'image-1']/@width";
287                xpathH = "jasper:detail/jasper:band/jasper:image/jasper:reportElement[./@key = 'image-1']/@height";
288                w = XMLTools.getRequiredNodeAsInt( xml.getRootElement(), xpathW, nsc );
289                h = XMLTools.getRequiredNodeAsInt( xml.getRootElement(), xpathH, nsc );
290            }
291            return new Pair<Integer, Integer>( w, h );
292        }
293    
294        protected double calcScale( Pair<Integer, Integer> size, String getmap )
295                                throws InconsistentRequestException, XMLParsingException, IOException, SAXException {
296            // TODO The map path is static. It should be instead read from somewhere else.
297            // A good idea would be to save the path in the web.xml of the corresponding application,
298            // or in controller.xml of the PdfPrintListener and sends it with rpc request
299    
300            Map<String, String> model = KVP2Map.toMap( getmap );
301            model.put( "ID", "22" );
302            GetMap gm = GetMap.create( model );
303    
304            // CoordinateSystem crs = CRSFactory.create( gm.getSrs() );
305    
306            // map size in template in metre; templates generated by iReport are designed
307            // to assume a resolution of 72dpi
308            double ms = ( size.first / 72d ) * 0.0254;
309            // TODO
310            // consider no metric CRS
311            return gm.getBoundingBox().getWidth() / ms;
312        }
313    
314        /**
315         * accesses the legend URLs passed, draws the result onto an image that are stored in a temporary file. The name of
316         * the file will be returned.
317         * 
318         * @param legends
319         * @return filename of image file
320         */
321        private String accessLegend( List<String[]> legends )
322                                throws IOException {
323            int width = Integer.parseInt( getInitParameter( "LEGENDWIDTH" ) );
324            int height = Integer.parseInt( getInitParameter( "LEGENDHEIGHT" ) );
325            String tmp = getInitParameter( "LEGENDBGCOLOR" );
326            if ( tmp == null ) {
327                tmp = "0xFFFFFF";
328            }
329            Color bg = Color.decode( tmp );
330            BufferedImage bi = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
331            Graphics g = bi.getGraphics();
332            g.setColor( bg );
333            g.fillRect( 0, 0, bi.getWidth(), bi.getHeight() );
334            g.setColor( Color.BLACK );
335            int k = 10;
336    
337            for ( int i = 0; i < legends.size(); i++ ) {
338                if ( k > bi.getHeight() ) {
339                    if ( LOG.getLevel() <= ILogger.LOG_WARNING ) {
340                        LOG.logWarning( "The necessary legend size is larger than the available legend space." );
341                    }
342                }
343                String[] s = legends.get( i );
344                if ( s[1] != null ) {
345                    LOG.logDebug( "reading legend: " + s[1] );
346                    Image img = null;
347                    try {
348                        img = ImageUtils.loadImage( new URL( s[1] ) );
349                    } catch ( Exception e ) {
350                        if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
351                            String msg = StringTools.concat( 400, "Exception for Layer: ", s[0], " - ", s[1] );
352                            LOG.logDebug( msg );
353                            LOG.logDebug( e.getLocalizedMessage() );
354                        }
355                        if ( getInitParameter( "MISSING_IMAGE" ) != null ) {
356                            String missingImageUrl = getHomePath() + getInitParameter( "MISSING_IMAGE" );
357                            File missingImage = new File( missingImageUrl );
358                            if ( missingImage.exists() ) {
359                                img = ImageUtils.loadImage( missingImage );
360                            }
361                        }
362                    }
363                    if ( img != null ) {
364                        if ( img.getWidth( null ) < 50 ) {
365                            // it is assumed that no label is assigned
366                            g.drawImage( img, 0, k, null );
367                            g.drawString( s[0], img.getWidth( null ) + 10, k + img.getHeight( null ) / 2 );
368                        } else {
369                            g.drawImage( img, 0, k, null );
370                        }
371                        k = k + img.getHeight( null ) + 10;
372                    }
373                } else {
374                    g.drawString( "- " + s[0], 0, k + 10 );
375                    k = k + 20;
376                }
377            }
378            g.dispose();
379    
380            return storeImage( bi );
381        }
382    
383        /**
384         * performs the GetMap requests passed, draws the result onto an image that are stored in a temporary file. The name
385         * of the file will be returned.
386         * 
387         * @param list
388         * @return filename of image file
389         * @throws PortalException
390         * @throws IOException
391         */
392        private String performGetMapRequests( List<String> list )
393                                throws PortalException, IOException {
394    
395            Map<String, String> map = KVP2Map.toMap( list.get( 0 ) );
396            map.put( "ID", "ww" );
397            GetMap getMap = null;
398            try {
399                getMap = GetMap.create( map );
400            } catch ( Exception e ) {
401                LOG.logError( e.getMessage(), e );
402                String s = Messages.format( "AbstractSimplePrintListener.GETMAPCREATION", list.get( 0 ) );
403                throw new PortalException( s );
404            }
405            BufferedImage bi = new BufferedImage( getMap.getWidth(), getMap.getHeight(), BufferedImage.TYPE_INT_ARGB );
406            Graphics g = bi.getGraphics();
407            for ( int i = 0; i < list.size(); i++ ) {
408                URL url = new URL( list.get( i ) );
409                Image img = null;
410                try {
411                    img = ImageUtils.loadImage( url );
412                } catch ( Exception e ) {
413                    // This is the case where a getmap request produces an error. This does not definitly mean that
414                    // the wms is not working, it could also be because the bounding box is not correct or too big. Try to
415                    // zoom
416                    // in, you might find something
417                    LOG.logInfo( "could not load map from: ", url.toExternalForm() );
418                }
419                g.drawImage( img, 0, 0, null );
420            }
421            g.dispose();
422            return storeImage( bi );
423        }
424    
425        /**
426         * stores the passed image in the defined temporary directory and returns the dynamicly created filename
427         * 
428         * @param bi
429         * @return filename of image file
430         * @throws IOException
431         */
432        private String storeImage( BufferedImage bi )
433                                throws IOException {
434    
435            String s = UUID.randomUUID().toString();
436            String tempDir = getInitParameter( "TEMPDIR" );
437            if ( !tempDir.endsWith( "/" ) ) {
438                tempDir = tempDir + '/';
439            }
440            if ( tempDir.startsWith( "/" ) ) {
441                tempDir = tempDir.substring( 1, tempDir.length() );
442            }
443            ServletContext sc = ( (HttpServletRequest) this.getRequest() ).getSession( true ).getServletContext();
444            String fileName = StringTools.concat( 300, sc.getRealPath( tempDir ), '/', s, ".png" );
445    
446            FileOutputStream fos = new FileOutputStream( new File( fileName ) );
447    
448            ImageUtils.saveImage( bi, fos, "png", 1 );
449            fos.close();
450    
451            return fileName;
452        }
453    
454        private void forwardPDF( Object result )
455                                throws PortalException {
456            // must be a byte array
457            String tempDir = getInitParameter( "TEMPDIR" );
458            if ( !tempDir.endsWith( "/" ) ) {
459                tempDir = tempDir + '/';
460            }
461            if ( tempDir.startsWith( "/" ) ) {
462                tempDir = tempDir.substring( 1, tempDir.length() );
463            }
464            ServletContext sc = ( (HttpServletRequest) this.getRequest() ).getSession( true ).getServletContext();
465    
466            String fileName = UUID.randomUUID().toString();
467            String s = StringTools.concat( 200, sc.getRealPath( tempDir ), '/', fileName, ".pdf" );
468            try {
469                RandomAccessFile raf = new RandomAccessFile( s, "rw" );
470                raf.write( (byte[]) result );
471                raf.close();
472            } catch ( Exception e ) {
473                e.printStackTrace();
474                LOG.logError( "could not write temporary pdf file: " + s, e );
475                throw new PortalException( Messages.format( "AbstractSimplePrintListener.PDFCREATION", s ), e );
476            }
477    
478            getRequest().setAttribute( "PDF", StringTools.concat( 200, tempDir, fileName, ".pdf" ) );
479        }
480    
481        private void forwardImage( Image result, String format )
482                                throws PortalException {
483    
484            format = format.substring( format.indexOf( '/' ) + 1 );
485    
486            String tempDir = getInitParameter( "TEMPDIR" );
487            if ( !tempDir.endsWith( "/" ) ) {
488                tempDir = tempDir + '/';
489            }
490            if ( tempDir.startsWith( "/" ) ) {
491                tempDir = tempDir.substring( 1, tempDir.length() );
492            }
493            ServletContext sc = ( (HttpServletRequest) this.getRequest() ).getSession( true ).getServletContext();
494    
495            String fileName = UUID.randomUUID().toString();
496            String s = StringTools.concat( 200, sc.getRealPath( tempDir ), "/", fileName, ".", format );
497            try {
498                // make sure we have a BufferedImage
499                if ( !( result instanceof BufferedImage ) ) {
500                    BufferedImage img = new BufferedImage( result.getWidth( null ), result.getHeight( null ),
501                                                           BufferedImage.TYPE_INT_ARGB );
502    
503                    Graphics g = img.getGraphics();
504                    g.drawImage( result, 0, 0, null );
505                    g.dispose();
506                    result = img;
507                }
508    
509                ImageUtils.saveImage( (BufferedImage) result, s, 1 );
510            } catch ( Exception e ) {
511                LOG.logError( "could not write temporary pdf file: " + s, e );
512                throw new PortalException( Messages.format( "AbstractSimplePrintListener.PDFCREATION", s ), e );
513            }
514    
515            getRequest().setAttribute( "PDF", StringTools.concat( 200, tempDir, fileName, ".", format ) );
516        }
517    
518        /**
519         * fills the passed PrintMap request template with required values
520         * 
521         * @param vc
522         * @return returns a list with all base requests
523         */
524        private List<String> createGetMapRequests( ViewContext vc, RPCWebEvent rpc, Pair<Integer, Integer> size ) {
525    
526            RPCStruct struct = (RPCStruct) rpc.getRPCMethodCall().getParameters()[1].getValue();
527            Integer dpi = null;
528            if ( struct.getMember( "DPI" ) != null ) {
529                dpi = Integer.parseInt( struct.getMember( "DPI" ).getValue().toString() );
530            }
531            LOG.logInfo( "dpi: ", dpi );
532    
533            User user = getUser();
534            String vsp = getVendorspecificParameters( rpc );
535    
536            // set boundingbox/envelope
537            Point[] points = vc.getGeneral().getBoundingBox();
538            Envelope bbox = GeometryFactory.createEnvelope( points[0].getPosition(), points[1].getPosition(),
539                                                            points[0].getCoordinateSystem() );
540    
541            int width = Integer.parseInt( getInitParameter( "WIDTH" ) );
542            int height = Integer.parseInt( getInitParameter( "HEIGHT" ) );
543            if ( dpi != null ) {
544                width = (int) Math.round( size.first * ( dpi / 72d ) );
545                height = (int) Math.round( size.second * ( dpi / 72d ) );
546            }
547    
548            bbox = MapUtils.ensureAspectRatio( bbox, width, height );
549    
550            StringBuffer sb = new StringBuffer( 1000 );
551            sb.append( "&BBOX=" ).append( bbox.getMin().getX() ).append( ',' );
552            sb.append( bbox.getMin().getY() ).append( ',' ).append( bbox.getMax().getX() );
553            sb.append( ',' ).append( bbox.getMax().getY() ).append( "&WIDTH=" );
554            sb.append( width ).append( "&HEIGHT=" ).append( height );
555            if ( user != null ) {
556                sb.append( "&user=" ).append( user.getName() );
557                sb.append( "&password=" ).append( user.getPassword() );
558            }
559            if ( vsp != null ) {
560                sb.append( "&" ).append( vsp );
561            }
562            String sessionId = (String) ( (HttpServletRequest) getRequest() ).getSession().getAttribute( "SESSIONID" );
563            if ( sessionId != null ) {
564                sb.append( "&sessionid=" ).append( sessionId );
565            }
566            String[] reqs = PortalUtils.createBaseRequests( vc );
567            List<String> list = new ArrayList<String>( reqs.length );
568            for ( int i = 0; i < reqs.length; i++ ) {
569                list.add( reqs[i] + sb.toString() );
570                LOG.logDebug( "GetMap request:", reqs[i] + sb.toString() );
571            }
572    
573            return list;
574        }
575    
576        /**
577         * returns <code>null</code> and should be overwritten by an extending class
578         * 
579         * @return <code>null</code>
580         */
581        protected String getVendorspecificParameters( RPCWebEvent rpc ) {
582            // TODO Auto-generated method stub
583            return null;
584        }
585    
586        /**
587         * returns <code>null</code> and should be overwritten by an extending class
588         * 
589         * @return <code>null</code>
590         */
591        protected User getUser() {
592            return null;
593        }
594    
595        /**
596         * reads the view context to print from the users session
597         * 
598         * @param rpc
599         * @return the viewcontext defined by the rpc
600         */
601        abstract protected ViewContext getViewContext( RPCWebEvent rpc );
602    
603        /**
604         * returns legend access URLs for all visible layers of the passed view context. If a visible layer does not define
605         * a LegendURL
606         * 
607         * @param vc
608         * @return legend access URLs for all visible layers of the passed view context. If a visible layer does not define
609         *         a LegendURL
610         */
611        private List<String[]> createLegendURLs( ViewContext vc ) {
612            Layer[] layers = vc.getLayerList().getLayers();
613            List<String[]> list = new ArrayList<String[]>();
614            for ( int i = 0; i < layers.length; i++ ) {
615                if ( !layers[i].isHidden() ) {
616                    Style style = layers[i].getStyleList().getCurrentStyle();
617                    String[] s = new String[2];
618                    s[0] = layers[i].getTitle();
619                    if ( style.getLegendURL() != null ) {
620                        s[1] = style.getLegendURL().getOnlineResource().toExternalForm();
621                    }
622                    list.add( s );
623                }
624            }
625            return list;
626        }
627    
628        /**
629         * validates the incoming request/RPC if conatins all required elements
630         * 
631         * @param rpc
632         * @throws PortalException
633         */
634        protected void validate( RPCWebEvent rpc )
635                                throws PortalException {
636            RPCStruct struct = (RPCStruct) rpc.getRPCMethodCall().getParameters()[1].getValue();
637            if ( struct.getMember( "TEMPLATE" ) == null ) {
638                throw new PortalException( Messages.getString( "portal.common.control.VALIDATIONERROR" ) );
639            }
640    
641            if ( rpc.getRPCMethodCall().getParameters()[0].getValue() == null ) {
642                throw new PortalException( Messages.getString( "portal.common.control.VALIDATIONERROR" ) );
643            }
644        }
645    
646    }