KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > blandware > atleap > webapp > util > core > WebappUtil


1 /*
2  * Copyright 2004 Blandware (http://www.blandware.com)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package com.blandware.atleap.webapp.util.core;
17
18 import com.blandware.atleap.common.Constants;
19 import com.blandware.atleap.common.NewsModuleConstants;
20 import com.blandware.atleap.common.TestimonialModuleConstants;
21 import com.blandware.atleap.common.util.CommonConverter;
22 import com.blandware.atleap.common.util.ConvertUtil;
23 import com.blandware.atleap.common.util.PartialCollection;
24 import com.blandware.atleap.common.util.StringUtil;
25 import com.blandware.atleap.model.core.*;
26 import com.blandware.atleap.service.core.ContentResourceManager;
27 import com.blandware.atleap.service.core.LayoutManager;
28 import com.blandware.atleap.service.core.LookupManager;
29 import com.blandware.atleap.service.core.PageManager;
30 import com.blandware.atleap.service.news.NewsManager;
31 import com.blandware.atleap.service.testimonials.TestimonialManager;
32 import com.blandware.atleap.webapp.struts.HeritableComponentDefinition;
33 import com.blandware.atleap.webapp.util.news.NewsModuleWebConstants;
34 import com.blandware.atleap.webapp.util.testimonials.TestimonialModuleWebConstants;
35 import org.apache.commons.beanutils.BeanUtils;
36 import org.apache.commons.beanutils.ConvertUtils;
37 import org.apache.commons.beanutils.PropertyUtils;
38 import org.apache.struts.Globals;
39 import org.apache.struts.action.ActionMapping;
40 import org.apache.struts.config.ForwardConfig;
41 import org.apache.struts.config.ModuleConfig;
42 import org.apache.struts.tiles.DefinitionsFactoryException;
43 import org.apache.struts.tiles.TilesUtil;
44 import org.apache.struts.util.MessageResources;
45 import org.apache.struts.util.ModuleUtils;
46 import org.apache.struts.util.RequestUtils;
47 import org.springframework.context.ApplicationContext;
48 import org.springframework.web.context.support.WebApplicationContextUtils;
49
50 import javax.servlet.ServletContext JavaDoc;
51 import javax.servlet.http.HttpServletRequest JavaDoc;
52 import javax.servlet.http.HttpServletResponse JavaDoc;
53 import java.io.UnsupportedEncodingException JavaDoc;
54 import java.lang.reflect.InvocationTargetException JavaDoc;
55 import java.net.MalformedURLException JavaDoc;
56 import java.net.URLEncoder JavaDoc;
57 import java.nio.charset.Charset JavaDoc;
58 import java.util.*;
59
60 /**
61  * <p>Utils to use in web module</p>
62  * <p><a HREF="WebappUtil.java.htm"><i>View Source</i></a></p>
63  *
64  * @author Andrey Grebnev <a HREF="mailto:andrey.grebnev@blandware.com">&lt;andrey.grebnev@blandware.com&gt;</a>
65  * @author Sergey Zubtcovskii <a HREF="mailto:sergey.zubtcovskii@blandware.com">&lt;sergey.zubtcovskii@blandware.com&gt;</a>
66  * @version $Revision: 1.52 $ $Date: 2006/03/26 13:51:47 $
67  */

68 public class WebappUtil {
69
70     /**
71      * Gets index of indexed ContentField (it's extracted from identifier)
72      *
73      * @param identifier e.g. a[0.5]
74      * @return index or <code>null</code> if no index found or it cannot be
75      * converted to Double
76      */

77     public static String JavaDoc getContentFieldIndex(String JavaDoc identifier) {
78         if ( identifier == null ) {
79             return null;
80         }
81
82         String JavaDoc result = null;
83         int openBracket = identifier.lastIndexOf("[");
84         int closeBracket = identifier.lastIndexOf("]");
85         if ( openBracket > 0 && closeBracket > 2 && closeBracket - openBracket > 1 ) {
86             try {
87                 // this is done just to check whether index value is valid number
88
Double.valueOf(identifier.substring(openBracket + 1, closeBracket));
89                 result = identifier.substring(openBracket + 1, closeBracket);
90             } catch ( Exception JavaDoc ex ) {
91                 //do nothing
92
}
93         }
94         return result;
95     }
96
97     /**
98      * A comparator used to compare indexed content fields. It compares
99      * them by their index value.
100      */

101     public static class IndexedContentFieldComparator implements Comparator {
102         /**
103          * Compares CFs by their index values. If first is less than second,
104          * -1 is returned, if they are equal, 0 is returned, otherwise +1 is the
105          * result
106          *
107          * @param o1 First field
108          * @param o2 Second field
109          * @return -1, 0 or 1
110          */

111         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
112             if ( !(o1 instanceof ContentField) || !(o2 instanceof ContentField) ) {
113                 throw new ClassCastException JavaDoc("Only ContentFields can be compared by this comparator");
114             }
115
116             ContentField cf1 = (ContentField) o1;
117             ContentField cf2 = (ContentField) o2;
118
119             String JavaDoc index1 = getContentFieldIndex(cf1.getIdentifier());
120             String JavaDoc index2 = getContentFieldIndex(cf2.getIdentifier());
121
122             if ( index1 == null || index2 == null ) {
123                 throw new ClassCastException JavaDoc("Only Indexed ContentFields can be compared by this comparator");
124             }
125
126             Double JavaDoc i1 = Double.valueOf(index1);
127             Double JavaDoc i2 = Double.valueOf(index2);
128
129             return i1.compareTo(i2);
130         }
131     }
132
133
134     /**
135      * Joins two collections: parent field collection and child field collection.
136      * If some field (from parent field collection) with the same identifier
137      * exists in child field collection, it will be overriden.
138      *
139      * @param parentFields collection of fields with lower precedence
140      * @param childFields collection of fields with higher precedense
141      * @return joined collection
142      */

143     public static Collection joinFields(Collection parentFields, Collection childFields) {
144         if ( parentFields == null || parentFields.size() == 0 ) {
145             return childFields;
146         }
147         if ( childFields == null || childFields.size() == 0 ) {
148             return parentFields;
149         }
150         Map fields = new HashMap();
151         for ( Iterator iterator = parentFields.iterator(); iterator.hasNext(); ) {
152             ContentField contentField = (ContentField) iterator.next();
153             String JavaDoc key = contentField.getIdentifier();
154             fields.put(key, contentField);
155         }
156         for ( Iterator iterator = childFields.iterator(); iterator.hasNext(); ) {
157             ContentField contentField = (ContentField) iterator.next();
158             String JavaDoc key = contentField.getIdentifier();
159             fields.put(key, contentField);
160         }
161         return fields.values();
162     }
163
164     /**
165      * Converts collection of <code>Role</code> objects to comma-separated list
166      * of their names (identifiers)
167      *
168      * @param roles Collection of roles
169      * @return Comma-separated list of roles
170      */

171     public static String JavaDoc rolesToString(Collection roles) {
172         if ( roles == null || roles.size() == 0 ) {
173             return "";
174         }
175         List roleNames = new ArrayList();
176         //getting names of roles
177
for ( Iterator iterator = roles.iterator(); iterator.hasNext(); ) {
178             Role role = (Role) iterator.next();
179             roleNames.add(role.getName());
180         }
181         return ConvertUtil.convertListToString(roleNames, ",");
182     }
183
184     /**
185      * Returns the form action converted into a server-relative URL adding a
186      * default locale suffix to it.
187      *
188      * @param action can be action name or full action with extension and query string
189      * @param module struts module name, if <code>null</code> the current will be used
190      * @param request Servlet request we are proceeding
191      * @param urlType Value to mark URL must be domain, context or module relative
192      * If it is equal to <code>URL_DOMAIN_RELATIVE</code> resulting value will include context path and module prefix
193      * Else if it is equal to <code>URL_CONTEXT_RELATIVE</code> resulting value will include module prefix only
194      * Else resulting value will include only URL itself without any prefixes.
195      * @return URL of requested action mapping
196      */

197     public static String JavaDoc getActionMappingURL(String JavaDoc action, String JavaDoc module, HttpServletRequest JavaDoc request, int urlType) {
198         return getActionMappingURL(action, module, request, urlType, true);
199     }
200
201     /**
202      * Returns the form action converted into a server-relative URL.
203      *
204      * @param action can be action name or full action with extension and query string
205      * @param module struts module name, if <code>null</code> the current will be used
206      * @param request Servlet request we are proceeding
207      * @param urlType Value to mark URL must be domain, context or module relative
208      * If it is equal to <code>URL_DOMAIN_RELATIVE</code> resulting value will include context path and module prefix
209      * Else if it is equal to <code>URL_CONTEXT_RELATIVE</code> resulting value will include module prefix only
210      * Else resulting value will include only URL itself without any prefixes.
211      * @param addLocaleSuffix Whether or not to add default locale suffix
212      * @return URL of requested action mapping
213      */

214     public static String JavaDoc getActionMappingURL(String JavaDoc action, String JavaDoc module, HttpServletRequest JavaDoc request, int urlType, boolean addLocaleSuffix) {
215         Locale locale = RequestUtils.getUserLocale(request, null);
216         String JavaDoc language = null;
217         if ( locale != null && addLocaleSuffix ) {
218             language = locale.getLanguage();
219         }
220         return getActionMappingURL(action, module, request, urlType, language);
221     }
222
223
224     /**
225      * Returns the form action converted into a server-relative URL.
226      *
227      * @param action can be action name or full action with extension and query string
228      * @param module struts module name, if <code>null</code> the current will be used
229      * @param request Servlet request we are proceeding
230      * @param urlType Value to mark URL must be domain, context or module relative
231      * If it is equal to <code>URL_DOMAIN_RELATIVE</code> resulting value will include context path and module prefix
232      * Else if it is equal to <code>URL_CONTEXT_RELATIVE</code> resulting value will include module prefix only
233      * Else resulting value will include only URL itself without any prefixes.
234      * @param localeSuffix Locale suffix to add
235      * @return URL of requested action mapping
236      */

237     public static String JavaDoc getActionMappingURL(String JavaDoc action, String JavaDoc module, HttpServletRequest JavaDoc request, int urlType, String JavaDoc localeSuffix) {
238
239         StringBuffer JavaDoc url = new StringBuffer JavaDoc();
240         ServletContext JavaDoc servletContext = request.getSession().getServletContext();
241         ModuleConfig moduleConfig = ModuleUtils.getInstance().getModuleConfig(module, request, servletContext);
242
243         // Use our servlet mapping, if one is specified
244
String JavaDoc servletMapping = (String JavaDoc) servletContext.getAttribute(Globals.SERVLET_KEY);
245
246         // append context path if requested
247
if ( urlType == WebappConstants.URL_TYPE_DOMAIN_RELATIVE ) {
248             url.append(request.getContextPath());
249         }
250
251         // append an /rw prefix
252
if ( servletMapping != null && servletMapping.startsWith("*.") ) {
253             if ( localeSuffix != null && localeSuffix.trim().length() > 0 && !action.startsWith(Constants.LOCALIZED_URI_PREFIX) ) {
254                 url.append(Constants.LOCALIZED_URI_PREFIX);
255             }
256         }
257
258         // append module prefix if requested
259
if ( (urlType == WebappConstants.URL_TYPE_DOMAIN_RELATIVE || urlType == WebappConstants.URL_TYPE_CONTEXT_RELATIVE) && moduleConfig != null ) {
260             url.append(moduleConfig.getPrefix());
261         }
262
263         // construct an URL for specified action
264
if ( servletMapping != null ) {
265
266             String JavaDoc queryString = null;
267             int questionMark = action.indexOf("?");
268             if ( questionMark >= 0 ) {
269                 queryString = action.substring(questionMark);
270             }
271
272             String JavaDoc actionMapping = getActionMappingName(action);
273             if ( servletMapping.startsWith("*.") ) {
274
275                 url.append(actionMapping);
276                 if ( localeSuffix != null && localeSuffix.trim().length() > 0 ) {
277                     url.append(".").append(localeSuffix);
278                 }
279                 url.append(servletMapping.substring(1));
280             } else if ( servletMapping.endsWith("/*") ) {
281                 url.append(servletMapping.substring(0, servletMapping.length() - 2));
282                 url.append(actionMapping);
283
284             } else if ( servletMapping.equals("/") ) {
285                 url.append(actionMapping);
286             }
287
288             if ( queryString != null ) {
289                 url.append(queryString);
290             }
291         }
292
293         // Otherwise, assume extension mapping is in use and extension is
294
// already included in the action property
295
else {
296             if ( !action.startsWith("/") ) {
297                 url.append("/");
298             }
299             url.append(action);
300         }
301
302         return url.toString();
303     }
304
305     /**
306      * Returns the form action converted into an action mapping path. The
307      * value of the <code>action</code> property is manipulated as follows in
308      * computing the name of the requested mapping:
309      * <ul>
310      * <li>Any filename extension is removed (in the theory that extension
311      * mapping is being used to select the controller servlet).</li>
312      * <li>If the resulting value does not start with a slash, then a
313      * slash is prepended.</li>
314      * </ul>
315      *
316      * @param action action URI
317      * @return mapping name
318      */

319     protected static String JavaDoc getActionMappingName(String JavaDoc action) {
320
321         String JavaDoc value = action;
322         int question = action.indexOf("?");
323         if ( question >= 0 ) {
324             value = value.substring(0, question);
325         }
326
327         int slash = value.lastIndexOf("/");
328         int period = value.lastIndexOf(".");
329         if ( (period >= 0) && (period > slash) ) {
330             value = value.substring(0, period);
331         }
332
333         return value.startsWith("/") ? value : ("/" + value);
334     }
335
336     /**
337      * Searches for configuration object for specified Global Action Forward
338      *
339      * @param globalForward Name of Global Forward to find config for
340      * @param module Name of module or <code>null</code> if current is used
341      * @param request HTTP Servlet request we're processing
342      * @return Configuration object for specified Global Forward or <code>null</code>
343      */

344     public static ForwardConfig findGlobalForwardConfig(String JavaDoc globalForward, String JavaDoc module, HttpServletRequest JavaDoc request) {
345         ServletContext JavaDoc servletContext = request.getSession().getServletContext();
346         ModuleConfig moduleConfig = ModuleUtils.getInstance().getModuleConfig(module, request, servletContext);
347         ForwardConfig forwardConfig = null;
348         if ( moduleConfig != null ) {
349             forwardConfig = moduleConfig.findForwardConfig(globalForward);
350         }
351         return forwardConfig;
352     }
353
354
355     /**
356      * Returns the URL corresponding to specified Global Action Forward adding
357      * a default locale suffix
358      *
359      * @param globalForward Global forward name
360      * @param module struts module name. If <code>null</code>, the current will be used
361      * @param request Servlet request we are proceeding
362      * @param urlType URL type
363      * @return URL corresponding to the specified Global Action Forward
364      */

365     public static String JavaDoc getActionForwardURL(String JavaDoc globalForward, String JavaDoc module, HttpServletRequest JavaDoc request, int urlType) throws MalformedURLException JavaDoc {
366         return getActionForwardURL(globalForward, module, request, urlType, true);
367     }
368
369     /**
370      * Returns the URL corresponding to specified Global Action Forward
371      *
372      * @param globalForward Global forward name
373      * @param module struts module name. If <code>null</code>, the current will be used
374      * @param request Servlet request we are proceeding
375      * @param urlType URL type
376      * @param addLocaleSuffix Whether or not to add default locale suffix
377      * @return URL corresponding to the specified Global Action Forward
378      */

379     public static String JavaDoc getActionForwardURL(String JavaDoc globalForward, String JavaDoc module, HttpServletRequest JavaDoc request, int urlType, boolean addLocaleSuffix) throws MalformedURLException JavaDoc {
380         Locale locale = RequestUtils.getUserLocale(request, null);
381         String JavaDoc language = null;
382         if ( locale != null && addLocaleSuffix ) {
383             language = locale.getLanguage();
384         }
385         return getActionForwardURL(globalForward, module, request, urlType, language);
386     }
387
388     /**
389      * Returns the URL corresponding to specified Global Action Forward
390      *
391      * @param globalForward Global forward name
392      * @param module Struts module name. If <code>null</code>, current will be used
393      * @param request Servlet request we are proceeding
394      * @param urlType URL type
395      * @param localeSuffix Locale suffix to add
396      * @return URL corresponding to the specified Global Action Forward
397      */

398     public static String JavaDoc getActionForwardURL(String JavaDoc globalForward, String JavaDoc module, HttpServletRequest JavaDoc request, int urlType, String JavaDoc localeSuffix) throws MalformedURLException JavaDoc {
399         ForwardConfig forwardConfig = findGlobalForwardConfig(globalForward, module, request);
400         if ( forwardConfig == null ) {
401             throw new MalformedURLException JavaDoc("No global forward with name '" + globalForward + "' could be found");
402         }
403         return getActionForwardURL(forwardConfig, module, request, urlType, localeSuffix);
404     }
405
406     /**
407      * Returns the URL corresponding to specified ActionForward adding a default
408      * locale suffix
409      *
410      * @param forwardConfig ForwardConfig instance, representing logical ActionForward to get URL for
411      * @param module struts module name. If <code>null</code>, the current will be used
412      * @param request Servlet request we are proceeding
413      * @param urlType URL type
414      * @return URL corresponding to the specified Global ActionForward
415      */

416     public static String JavaDoc getActionForwardURL(ForwardConfig forwardConfig, String JavaDoc module, HttpServletRequest JavaDoc request, int urlType) {
417         return getActionForwardURL(forwardConfig, module, request, urlType, true);
418     }
419
420     /**
421      * Returns the URL corresponding to specified ActionForward
422      *
423      * @param forwardConfig ForwardConfig instance, representing logical ActionForward to get URL for
424      * @param module struts module name. If <code>null</code>, the current will be used
425      * @param request Servlet request we are proceeding
426      * @param urlType URL type
427      * @param addLocaleSuffix Whether or not to add default locale suffix
428      * @return URL corresponding to the specified Global Action Forward
429      */

430     public static String JavaDoc getActionForwardURL(ForwardConfig forwardConfig, String JavaDoc module, HttpServletRequest JavaDoc request, int urlType, boolean addLocaleSuffix) {
431         Locale locale = RequestUtils.getUserLocale(request, null);
432         String JavaDoc language = null;
433         if ( locale != null && addLocaleSuffix ) {
434             language = locale.getLanguage();
435         }
436         return getActionForwardURL(forwardConfig, module, request, urlType, language);
437     }
438
439     /**
440      * Return the URL corresponding to specified ActionForward
441      *
442      * @param forwardConfig ForwardConfig instance, representing logical ActionForward to get URL for
443      * @param module struts module name. If <code>null</code>, the current will be used
444      * @param request Servlet request we are proceeding
445      * @param urlType URL type
446      * @param localeSuffix Locale suffix to add (can be null)
447      * @return URL corresponding to the specified Global Action Forward
448      */

449     public static String JavaDoc getActionForwardURL(ForwardConfig forwardConfig, String JavaDoc module, HttpServletRequest JavaDoc request, int urlType, String JavaDoc localeSuffix) {
450         StringBuffer JavaDoc url = new StringBuffer JavaDoc();
451         ServletContext JavaDoc servletContext = request.getSession().getServletContext();
452         ModuleConfig moduleConfig = ModuleUtils.getInstance().getModuleConfig(module, request, servletContext);
453         String JavaDoc path = forwardConfig.getPath();
454
455         if ( !isExternalURL(path, request) ) {
456
457             if ( !isAbsoluteURL(path) ) {
458                 if ( urlType == WebappConstants.URL_TYPE_DOMAIN_RELATIVE ) {
459                     String JavaDoc contextPath = request.getContextPath();
460                     if ( !path.startsWith(contextPath) && !contextPath.equals("/") ) {
461                         url.append(contextPath);
462                     }
463                 }
464                 url.append(RequestUtils.forwardURL(request, forwardConfig, moduleConfig));
465             } else {
466                 url.append(path);
467             }
468
469             // add locale suffix if requested
470
if ( localeSuffix != null && localeSuffix.trim().length() > 0 ) {
471                 // Use our servlet mapping, if one is specified
472
String JavaDoc servletMapping = (String JavaDoc) servletContext.getAttribute(Globals.SERVLET_KEY);
473                 String JavaDoc ext = null;
474                 if ( servletMapping != null && servletMapping.startsWith("*.") ) {
475                     ext = servletMapping.substring(1);
476                 } else {
477                     ext = ".jsp";
478                 }
479
480                 String JavaDoc temp = url.toString();
481                 int questionMark = url.indexOf("?");
482                 if ( questionMark >= 0 ) {
483                     temp = url.substring(0, questionMark);
484                 }
485
486                 // dot before extension
487
int extDot = temp.lastIndexOf(ext);
488                 if ( extDot < 0 && !ext.equals(".jsp") ) {
489                     extDot = temp.lastIndexOf(".jsp");
490                 }
491                 if ( extDot > 0 ) {
492
493                     // first insert an /rw prefix
494

495                     int fromIndex = 0;
496                     if ( isAbsoluteURL(path) ) {
497                         // look up scheme
498
fromIndex = path.indexOf("://");
499                         if ( fromIndex < 0 ) {
500                             fromIndex = path.indexOf(":") + 1;
501                         } else {
502                             fromIndex += 3;
503                         }
504                     }
505
506                     String JavaDoc contextPath = request.getContextPath();
507                     if ( contextPath == null || contextPath.length() == 0 ) {
508                         contextPath = "/";
509                     }
510
511                     // save suffix pos for later use
512
int suffixPos = extDot;
513
514                     // length of text inserted in url to use correct positions
515
int correction = 0;
516
517                     // insert prefix if it does not exist
518
int insertPos;
519                     if ("/".equals(contextPath)) {
520                         insertPos = url.indexOf(contextPath, fromIndex);
521                     } else {
522                         insertPos = url.indexOf(contextPath, fromIndex) + contextPath.length();
523                     }
524
525                     if ( url.indexOf(Constants.LOCALIZED_URI_PREFIX, insertPos) != insertPos ) {
526                         url.insert(insertPos, Constants.LOCALIZED_URI_PREFIX);
527                         correction = Constants.LOCALIZED_URI_PREFIX.length();
528                         suffixPos += correction;
529                     }
530
531                     temp = temp.substring(0, extDot);
532
533                     // dot before language
534
int langDot = temp.lastIndexOf(".");
535                     if ( langDot != -1 && langDot + correction == suffixPos - 3 ) {
536                         url.replace(langDot + correction, suffixPos, "." + localeSuffix);
537                     } else {
538                         url.insert(suffixPos, "." + localeSuffix);
539                     }
540                 }
541             }
542
543         } else {
544             url.append(path);
545         }
546
547         return url.toString();
548     }
549
550     /**
551      * Computes URL from given values. Either <code>action</code> or <code>forward</code> or <code>href</code> must be non-null.
552      * Encodes all non-ASCII characters (if <code>encode</code> is <code>true</code>) and adds <code>jsessionid</code> to the generated link.
553      * If URL is absolute, it will not be encoded. Default locale suffix is added
554      * to the result.
555      *
556      * @param action Name of Action
557      * @param forward Name of Global Action Forward
558      * @param href Link which will be added to result without changes to its body
559      * @param anchor Anchor to append to the end of URL
560      * @param parameters Parameters to add to generated link
561      * @param request HTTP Servlet request we're currently proceeding
562      * @param response HTTP Servlet response we're creating
563      * @param encode Whether or not to encode non-ASCII characters
564      * @param redirect Whether or not we're generating an URL to use in <code>javax.servlet.http.HttpServletResponse#sendRedirect(String)</code> method
565      * @return Generated URL
566      * @throws MalformedURLException if URL is malformed, e.g. Global Action Forward with specified name could not be found
567      * @see javax.servlet.http.HttpServletResponse#sendRedirect(String)
568      */

569     public static String JavaDoc computeURL(String JavaDoc action, String JavaDoc forward, String JavaDoc href, String JavaDoc anchor, Map parameters, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, boolean encode, boolean redirect) throws MalformedURLException JavaDoc {
570         return computeURL(action, forward, href, anchor, parameters, request, response, encode, redirect, true);
571     }
572
573     /**
574      * Computes URL from given values. Either <code>action</code> or <code>forward</code> or <code>href</code> must be non-null.
575      * Encodes all non-ASCII characters (if <code>encode</code> is true) and adds <code>jsessionid</code> to the generated link.
576      * If URL is absolute, it will not be encoded.
577      *
578      * @param action Name of Action to
579      * @param forward Name of Global Action Forward
580      * @param href Link which will be added to result without changes to its body
581      * @param anchor Anchor to append to the end of URL
582      * @param parameters Parameters to add to generated link
583      * @param request HTTP Servlet request we're currently proceeding
584      * @param response HTTP Servlet response we're creating
585      * @param encode Whether or not to encode non-ASCII characters
586      * @param redirect Whether or not we're generating an URL to use in <code>javax.servlet.http.HttpServletResponse#sendRedirect(String)</code> method
587      * @param addLocaleSuffix Whether or not to add default locale suffix
588      * @return Generated URL
589      * @throws MalformedURLException if URL is malformed, e.g. Global Action Forward with specified name could not be found
590      * @see javax.servlet.http.HttpServletResponse#sendRedirect(String)
591      */

592     public static String JavaDoc computeURL(String JavaDoc action, String JavaDoc forward, String JavaDoc href, String JavaDoc anchor, Map parameters, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, boolean encode, boolean redirect, boolean addLocaleSuffix) throws MalformedURLException JavaDoc {
593         Locale locale = RequestUtils.getUserLocale(request, null);
594         String JavaDoc language = null;
595         if ( locale != null && addLocaleSuffix ) {
596             language = locale.getLanguage();
597         }
598         return computeURL(action, forward, href, anchor, parameters, request, response, encode, redirect, language);
599     }
600
601
602     /**
603      * Computes URL from given values. Either <code>action</code> or <code>forward</code> or <code>href</code> must be non-null.
604      * Encodes all non-ASCII characters (if <code>encode</code> is true) and adds <code>jsessionid</code> to the generated link.
605      * If URL is absolute, it will not be encoded.
606      *
607      * @param action Name of Action to
608      * @param forward Name of Global Action Forward
609      * @param href Link which will be added to result without changes to its body
610      * @param anchor Anchor to append to the end of URL
611      * @param parameters Parameters to add to generated link
612      * @param request HTTP Servlet request we're currently proceeding
613      * @param response HTTP Servlet response we're creating
614      * @param encode Whether or not to encode non-ASCII characters
615      * @param redirect Whether or not we're generating an URL to use in <code>javax.servlet.http.HttpServletResponse#sendRedirect(String)</code> method
616      * @param localeSuffix Locale suffix to add
617      * @return Generated URL
618      * @throws MalformedURLException if URL is malformed, e.g. Global Action Forward with specified name could not be found
619      * @see javax.servlet.http.HttpServletResponse#sendRedirect(String)
620      */

621     public static String JavaDoc computeURL(String JavaDoc action, String JavaDoc forward, String JavaDoc href, String JavaDoc anchor, Map parameters, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, boolean encode, boolean redirect, String JavaDoc localeSuffix) throws MalformedURLException JavaDoc {
622
623         // check correctness of attributes
624
int n = 0;
625         if ( action != null ) {
626             n++;
627         }
628         if ( forward != null ) {
629             n++;
630         }
631         if ( href != null ) {
632             n++;
633         }
634
635         if ( n > 1 ) {
636             throw new MalformedURLException JavaDoc("One and only one of 'action', 'forward' or 'href' attributes must be specified");
637         } else if ( n == 0 ) {
638             return null;
639         }
640
641         StringBuffer JavaDoc url = null;
642
643         // flag to distinguish external URL from internal
644
boolean urlIsExternal = false;
645
646         if ( action != null ) {
647             url = new StringBuffer JavaDoc(getActionMappingURL(action, null, request, WebappConstants.URL_TYPE_DOMAIN_RELATIVE, localeSuffix));
648         } else if ( forward != null ) {
649             String JavaDoc urlString = getActionForwardURL(forward, null, request, WebappConstants.URL_TYPE_DOMAIN_RELATIVE, localeSuffix);
650             url = new StringBuffer JavaDoc(urlString);
651             urlIsExternal = isExternalURL(urlString, request);
652         } else if ( href != null ) {
653             urlIsExternal = isExternalURL(href, request);
654             url = new StringBuffer JavaDoc();
655
656             // if href is internal URL, process it and insert locale suffix if it was requested
657
if ( !urlIsExternal ) {
658                 // if href is internal URL and is not absolute, it means that it starts with slash
659
if ( !isAbsoluteURL(href) ) {
660                     String JavaDoc contextPath = request.getContextPath();
661                     if ( !href.startsWith(contextPath) && !contextPath.equals("/") ) {
662                         url.append(contextPath);
663                     }
664                 }
665
666                 url.append(href);
667
668                 int questionMark = url.indexOf("?");
669                 String JavaDoc temp = url.toString();
670                 if ( questionMark != -1 ) {
671                     temp = url.substring(0, questionMark);
672                 }
673
674                 // add locale suffix if requested
675
if ( localeSuffix != null && localeSuffix.trim().length() > 0 ) {
676                     String JavaDoc servletMapping = (String JavaDoc) request.getSession().getServletContext().getAttribute(Globals.SERVLET_KEY);
677                     String JavaDoc ext = null;
678                     if ( servletMapping != null && servletMapping.startsWith("*.") ) {
679                         ext = servletMapping.substring(1);
680                     } else {
681                         ext = ".jsp";
682                     }
683
684                     // dot before extension
685
int extDot = temp.lastIndexOf(ext);
686                     if ( extDot < 0 && !ext.equals(".jsp") ) {
687                         extDot = temp.lastIndexOf(".jsp");
688                     }
689                     if ( extDot > 0 ) {
690
691                         // first insert an /rw prefix
692

693                         int fromIndex = 0;
694                         if ( isAbsoluteURL(href) ) {
695                             // look up scheme
696
fromIndex = href.indexOf("://");
697                             if ( fromIndex < 0 ) {
698                                 fromIndex = href.indexOf(":") + 1;
699                             } else {
700                                 fromIndex += 3;
701                             }
702                         }
703
704                         String JavaDoc contextPath = request.getContextPath();
705                         if ( contextPath == null || contextPath.length() == 0 ) {
706                             contextPath = "/";
707                         }
708
709                         // save suffix pos for later use
710
int suffixPos = extDot;
711
712                         // length of text inserted in url to use correct positions
713
int correction = 0;
714
715                         // insert prefix if it does not exist
716
int insertPos;
717                         if ("/".equals(contextPath)) {
718                             insertPos = url.indexOf(contextPath, fromIndex);
719                         } else {
720                             insertPos = url.indexOf(contextPath, fromIndex) + contextPath.length();
721                         }
722
723                         if ( url.indexOf(Constants.LOCALIZED_URI_PREFIX, insertPos) != insertPos ) {
724                             url.insert(insertPos, Constants.LOCALIZED_URI_PREFIX);
725                             correction = Constants.LOCALIZED_URI_PREFIX.length();
726                             suffixPos += correction;
727                         }
728
729                         temp = temp.substring(0, extDot);
730
731                         // dot before language
732
int langDot = temp.lastIndexOf(".");
733                         if ( langDot != -1 && langDot + correction == suffixPos - 3 ) {
734                             url.replace(langDot + correction, suffixPos, "." + localeSuffix);
735                         } else {
736                             url.insert(suffixPos, "." + localeSuffix);
737                         }
738                     }
739                 }
740             } else {
741                 url.append(href);
742             }
743         }
744
745         // add anchor (replace any existing)
746
if ( anchor != null && anchor.trim().length() > 0 ) {
747             int anchorPos = url.indexOf("#");
748             if ( anchorPos > 0 ) {
749                 url.setLength(anchorPos);
750             }
751             url.append('#').append(anchor);
752         }
753
754         // attach query string
755
Map resultParams = new HashMap();
756         int k = url.indexOf("?");
757         if ( k != -1 ) {
758             String JavaDoc queryString = url.substring(k + 1);
759             url.setLength(k);
760             resultParams = RequestUtil.getRequestParametersFromString(queryString);
761             if ( parameters != null ) {
762                 for ( Iterator i = parameters.entrySet().iterator(); i.hasNext(); ) {
763                     Map.Entry entry = (Map.Entry) i.next();
764                     String JavaDoc key = (String JavaDoc) entry.getKey();
765                     Object JavaDoc value = entry.getValue();
766                     resultParams.put(key, RequestUtil.mergeValues(resultParams.get(key), value));
767                 }
768             }
769         } else if ( parameters != null ) {
770             resultParams.putAll(parameters);
771         }
772
773         if ( !resultParams.isEmpty() ) {
774             // save any existing anchor
775
int anchorPos = url.indexOf("#");
776             if ( anchorPos > 0 ) {
777                 anchor = url.substring(anchorPos);
778                 url.setLength(anchorPos);
779                 if ( encode ) {
780                     try {
781                         anchor = URLEncoder.encode(anchor, Constants.DEFAULT_ENCODING);
782                     } catch ( UnsupportedEncodingException JavaDoc e ) {
783                         // do nothing
784
}
785                 }
786             } else {
787                 anchor = null;
788             }
789
790             url.append("?").append(RequestUtil.createQueryStringFromMap(resultParams, "&", encode && !urlIsExternal));
791
792             // reappend anchor (if any)
793
if ( anchor != null && anchor.trim().length() > 0 ) {
794                 url.append('#').append(anchor);
795             }
796         }
797
798         String JavaDoc result = url.toString();
799
800         if ( !urlIsExternal ) {
801             if ( redirect ) {
802                 result = response.encodeRedirectURL(result);
803             } else {
804                 result = response.encodeURL(result);
805             }
806         }
807         return result;
808     }
809
810
811     /**
812      * Gets field value from specified map of values. Map must contain mappings of localeIdentifiers to concrete values.
813      * While searching, following rules are applied:
814      * <ul>
815      * <li>
816      * 1. If map is null or is empty, null is returned.
817      * </li>
818      * <li>
819      * 2. Otherwise, searching for mapping for <code>localeIdentifier</code>
820      * </li>
821      * <li>
822      * 2.5 Following steps are applied only if <code>complexSearch</code> is
823      * <code>true</code>
824      * </li>
825      * <li>
826      * 3. If nothing has been found in step 2, searching for default locale for our application
827      * </li>
828      * <li>
829      * 4. If still not found, returning first mapping value from specified map
830      * </li>
831      * </ul>
832      *
833      * @param values Map of values to search in
834      * @param localeIdentifier Locale identifier to get value for
835      * @param request HTTP Servlet Request containing information about our Servlet Context
836      * @param complexSearch Whether to use a bit more complex lookup algorithm
837      * @return Field value
838      */

839     public static String JavaDoc getFieldValue(Map values, String JavaDoc localeIdentifier, HttpServletRequest JavaDoc request, boolean complexSearch) {
840
841         if ( values == null || values.isEmpty() ) {
842             return null;
843         }
844
845         String JavaDoc value = (String JavaDoc) values.get(localeIdentifier);
846         if ( (value == null || value.length() == 0) && complexSearch ) {
847             // nothing found for specified locale, search for default
848
ContentLocale defaultLocale = LocaleUtil.getInstance(request.getSession().getServletContext()).getDefaultLocale();
849             value = (String JavaDoc) values.get(defaultLocale.getIdentifier());
850
851             if ( value == null || value.length() == 0 ) {
852                 // still not found, take first value in map
853
value = (String JavaDoc) values.values().iterator().next();
854             }
855         }
856
857         return value;
858     }
859
860     /**
861      * Replace extension in URI
862      *
863      * @param uri The URI to replace extension in
864      * @param newExtension The new extension
865      * @return URI with replaced extension
866      */

867     public static String JavaDoc changeUriExtension(String JavaDoc uri, String JavaDoc newExtension) {
868         int slash = uri.lastIndexOf("/");
869         int period = uri.lastIndexOf(".");
870         if ( (period >= 0) && (period > slash) ) {
871             String JavaDoc uriWithout = uri.substring(0, period);
872             return uriWithout + newExtension;
873         } else {
874             return uri;
875         }
876     }
877
878
879     /**
880      * Retrieves localized (if found) information string of specified localizable.
881      * For example, for layout it will be its name, for pages value of 'title'
882      * field for specified locale. If none was found for a specified locale,
883      * tries to search for value for default locale, if nothing found again --
884      * any locale may be used.
885      *
886      * @param localizableId ID of localizable to get information about
887      * @param request HTTP Servlet Request containing information about our Servlet Context and locale under key
888      * <code>org.apache.struts.Globals.LOCALE_KEY</code>
889      * @return Information about localizable with specified ID
890      */

891     public static String JavaDoc getLocalizableInfo(Long JavaDoc localizableId, HttpServletRequest JavaDoc request) {
892         ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext());
893         LookupManager lookupManager = (LookupManager) applicationContext.getBean(Constants.LOOKUP_MANAGER_BEAN);
894         Localizable owner = lookupManager.retrieveLocalizable(localizableId);
895         return getLocalizableInfo(owner, request);
896     }
897
898     /**
899      * Retrieves localized (if found) information string of specified localizable.
900      * For layout it will be its name, for pages value of 'title' field for
901      * specified locale. If none was found for a specified locale,
902      * tries to search for value for default locale, if nothing found again --
903      * any locale may be used.
904      * Returned value is properly encoded.
905      *
906      * @param localizable Localizable to get information about
907      * @param request HTTP Servlet Request containing information about our Servlet Context and locale under key
908      * <code>org.apache.struts.Globals.LOCALE_KEY</code>
909      * @return Information about specified localizable
910      */

911     public static String JavaDoc getLocalizableInfo(Localizable localizable, HttpServletRequest JavaDoc request) {
912         if ( localizable == null ) {
913             return new String JavaDoc();
914         }
915         String JavaDoc localizableInfo = new String JavaDoc();
916         if ( localizable instanceof Layout ) {
917             Layout layout = (Layout) localizable;
918             localizableInfo = layout.getName();
919         } else if ( localizable instanceof Page ) {
920             Map title = new HashMap();
921             ContentField titleField = (ContentField) localizable.getContentFieldsMap().get("title");
922             if ( titleField != null ) {
923                 for ( Iterator i = titleField.getContentFieldValues().iterator(); i.hasNext(); ) {
924                     ContentFieldValue contentFieldValue = (ContentFieldValue) i.next();
925                     title.put(contentFieldValue.getContentLocale().getIdentifier(), contentFieldValue.getSimpleValue());
926                 }
927                 Locale locale = RequestUtils.getUserLocale(request, null);
928                 localizableInfo = getFieldValue(title, locale.getLanguage(), request, true);
929             }
930         } else if ( localizable instanceof MailTemplate ) {
931             MailTemplate mailTemplate = (MailTemplate) localizable;
932             localizableInfo = mailTemplate.getIdentifier();
933         }
934
935         // encode HTML-sensitive chars
936
localizableInfo = StringUtil.htmlEncode(localizableInfo);
937
938         MessageResources resources = (MessageResources) request.getAttribute(Globals.MESSAGES_KEY);
939         String JavaDoc ownerClassName = localizable.getClass().getName();
940         // remove package
941
int k = ownerClassName.lastIndexOf('.');
942         ownerClassName = ownerClassName.substring(k + 1);
943         String JavaDoc key = "core.localizable.form.class." + ownerClassName;
944         Locale locale = RequestUtils.getUserLocale(request, null);
945
946         String JavaDoc msg = resources.getMessage(locale, key, localizableInfo);
947         return (msg == null || msg.length() == 0) ? localizableInfo : msg;
948     }
949
950     /**
951      * Returns <code>true</code> if map has non-null and non-empty values for all keys
952      *
953      * @param values Map of values to check
954      * @return True if map contains correct values
955      */

956     public static boolean hasCorrectValues(Map values) {
957         if (values == null)
958             return false;
959         boolean result = true;
960         for ( Iterator i = values.keySet().iterator(); i.hasNext(); ) {
961             String JavaDoc key = (String JavaDoc) i.next();
962             String JavaDoc value = (String JavaDoc) values.get(key);
963             result = result && (value != null && value.length() > 0);
964         }
965         return result;
966     }
967
968     /**
969      * <p>Copies properties from orig bean to dest for each case where property names are the same.
970      * Uses CommonConverter with appropriate locale stored in session to correctly convert date to string and vice versa.
971      * </p>
972      * <p>This method is synchronized, so it guarantees, that correct converters will be set for each request
973      * </p>
974      *
975      * @param dest Destination bean to copy properties to
976      * @param orig Original bean to copy properties from
977      * @param request Http servlet request we are processing
978      * @see com.blandware.atleap.common.util.CommonConverter#CommonConverter(java.util.Locale)
979      */

980     public static synchronized void copyProperties(Object JavaDoc dest, Object JavaDoc orig, HttpServletRequest JavaDoc request) throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc {
981
982         boolean requestSpecified = request != null;
983
984         CommonConverter converter = new CommonConverter();
985
986         if ( requestSpecified ) {
987             Locale locale = RequestUtils.getUserLocale(request, null);
988             converter = new CommonConverter(locale);
989         }
990
991         ConvertUtils.register(converter, Date.class);
992         ConvertUtils.register(converter, String JavaDoc.class);
993
994         BeanUtils.copyProperties(dest, orig);
995
996         if ( requestSpecified ) {
997             // Register default converters
998
ConvertUtils.register(new CommonConverter(), String JavaDoc.class);
999             ConvertUtils.register(new CommonConverter(), Date.class);
1000        }
1001
1002    }
1003
1004    /**
1005     * <p>Copies properties from orig bean to dest for each case where property names are the same.
1006     * Uses CommonConverter with default locale to convert date to string and vice versa.
1007     * </p>
1008     * <p>This method is synchronized, so it guarantees, that correct converters will be set for each request
1009     * </p>
1010     *
1011     * @param dest Destination bean to copy properties to
1012     * @param orig Original bean to copy properties from
1013     * @see com.blandware.atleap.common.util.CommonConverter#CommonConverter()
1014     */

1015    public static synchronized void copyProperties(Object JavaDoc dest, Object JavaDoc orig) throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc {
1016        copyProperties(dest, orig, null);
1017    }
1018
1019    /**
1020     * Returns set of indexed overridable field identifiers for specified
1021     * Localizable
1022     *
1023     * @param owner Localizable to retrieve allowed field identifiers for
1024     * @param request HttpServletRequest we are currently proceeding
1025     * @return Set of allowed identifiers
1026     * @throws DefinitionsFactoryException
1027     */

1028    public static Set getIndexedOverridableFieldIdentifiers(Localizable owner, HttpServletRequest JavaDoc request) throws DefinitionsFactoryException {
1029        return getOverridableFieldIdentifiers(owner, request, true, true);
1030    }
1031
1032    /**
1033     * Returns set of indexed overridable field identifiers for specified
1034     * Localizable
1035     *
1036     * @param owner Localizable to retrieve allowed field identifiers for
1037     * @param request HttpServletRequest we are currently proceeding
1038     * @return Set of allowed identifiers
1039     * @throws DefinitionsFactoryException
1040     */

1041    public static Set getUnIndexedOverridableFieldIdentifiers(Localizable owner, HttpServletRequest JavaDoc request) throws DefinitionsFactoryException {
1042        return getOverridableFieldIdentifiers(owner, request, true, false);
1043    }
1044
1045    /**
1046     * Returns set of overridable field identifiers for specified Localizable,
1047     * no matter whether they are indexed or not
1048     *
1049     * @param owner Localizable to retrieve allowed field identifiers for
1050     * @param request HttpServletRequest we are currently proceeding
1051     * @return Set of allowed identifiers
1052     * @throws DefinitionsFactoryException if some error has occured when trying to get parent layout of page's owner layout
1053     */

1054    public static Set getOverridableFieldIdentifiers(Localizable owner, HttpServletRequest JavaDoc request) throws DefinitionsFactoryException {
1055        return getOverridableFieldIdentifiers(owner, request, false, false);
1056    }
1057
1058    /**
1059     * Returns set of overridable field identifiers for specified Localizable
1060     *
1061     * @param owner Localizable to retrieve allowed field identifiers for
1062     * @param request HttpServletRequest we are currently proceeding
1063     * @param considerIndexed if this is false, then indexed and unindexed
1064     * fields will be returned; indexed parameter is ignored. Else indexed
1065     * parameter controlls what fields will be considered: indexed or unindexed.
1066     * @param indexed whether to return indexed or unindexed fields identifiers.
1067     * If considerIndexed is false, this is ignored.
1068     * @return Set of allowed identifiers
1069     * @throws DefinitionsFactoryException if some error has occured when trying to get parent layout of page's owner layout
1070     */

1071    public static Set getOverridableFieldIdentifiers(Localizable owner, HttpServletRequest JavaDoc request, boolean considerIndexed, boolean indexed) throws DefinitionsFactoryException {
1072
1073        ServletContext JavaDoc servletContext = request.getSession().getServletContext();
1074        ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
1075        LayoutManager layoutManager = (LayoutManager) applicationContext.getBean(Constants.LAYOUT_MANAGER_BEAN);
1076
1077        // First obtain list of all field identifiers from layouts that relate
1078
// to a given Localizable
1079
Set fieldIdentifiers = new HashSet();
1080        String JavaDoc layoutDefinition = null;
1081        if ( owner instanceof ContentPage || owner instanceof Layout ) {
1082            // For content page obtain identifiers of all fields from its
1083
// layout and all its parents; for layout obtain identifiers of
1084
// fields from it and all its parents
1085
if ( owner instanceof ContentPage ) {
1086                ContentPage contentPage = (ContentPage) owner;
1087                layoutDefinition = contentPage.getLayout().getDefinition();
1088            } else {
1089                Layout layout = (Layout) owner;
1090                layoutDefinition = layout.getDefinition();
1091            }
1092            do {
1093                Layout layout = layoutManager.findLayoutByDefinition(layoutDefinition);
1094                if ( layout != null && (!(owner instanceof Layout) || !layout.equals(owner)) ) {
1095                    // for layout, consider only fields from its parents
1096
fieldIdentifiers.addAll(layout.getContentFieldsMap().keySet());
1097                }
1098                layoutDefinition = ((HeritableComponentDefinition) TilesUtil.getDefinition(layoutDefinition, request, servletContext)).getExtends();
1099            } while ( layoutDefinition != null );
1100        } else if ( owner instanceof ActionPage ) {
1101            // For action page obtain identifiers of all fields from all layouts
1102
PartialCollection layouts = layoutManager.listLayouts(null);
1103            for ( Iterator i = layouts.iterator(); i.hasNext(); ) {
1104                Layout layout = (Layout) i.next();
1105                fieldIdentifiers.addAll(layout.getContentFieldsMap().keySet());
1106            }
1107        } else {
1108            return new HashSet();
1109        }
1110
1111        // Skip some fields
1112
Set identifiers = new HashSet();
1113        for ( Iterator i = fieldIdentifiers.iterator(); i.hasNext(); ) {
1114            String JavaDoc identifier = (String JavaDoc) i.next();
1115
1116            int k = identifier.indexOf('[');
1117            if ( k != -1 ) {
1118                identifier = identifier.substring(0, k);
1119            }
1120            if ( owner instanceof ContentPage || owner instanceof ActionPage ) {
1121                ContentField pageField = (ContentField) owner.getContentFieldsMap().get(identifier);
1122                if ( pageField != null && pageField.getInternal().booleanValue() ) {
1123                    // Skip internal fields for ContentPage or ActionPage
1124
continue;
1125                }
1126            } else if ( owner instanceof Layout ) {
1127/*
1128                if ( k == -1 ) {
1129                    // Skip non-indexed fields for Layout
1130                    continue;
1131                }
1132*/

1133            }
1134            boolean fieldIsIndexed = (k != -1);
1135            if (considerIndexed) {
1136                if ((fieldIsIndexed && !indexed) || (!fieldIsIndexed && indexed)) {
1137                    continue;
1138                }
1139            }
1140
1141            identifiers.add(identifier);
1142        }
1143        return identifiers;
1144    }
1145
1146    /**
1147     * Returns a set of field identifiers for field which belong explicitly to
1148     * a given Localizable. Only identifiers for unindexed fields are returned.
1149     *
1150     * @param localizable Localizable from which to obtain set of identifiers
1151     * @return set of field identifiers
1152     */

1153    public static Set getLocalizableUnIndexedFieldsIdentifiers(Localizable localizable) {
1154        Set result = new TreeSet();
1155        List fields = localizable.getContentFields();
1156        for (int i = 0; i < fields.size(); i++) {
1157            ContentField field = (ContentField) fields.get(i);
1158            if (field.getIndex() == null) {
1159                result.add(field.getIdentifierWithoutIndex());
1160            }
1161        }
1162        return result;
1163    }
1164
1165    /**
1166     * Returns set of indexed field identifiers
1167     *
1168     * @param layoutDefinition Definition of layout to search fields on (all parent layouts will also be searched)
1169     * @param request HttpServletRequest we are currently processing
1170     * @return Set of indexed identifiers
1171     * @throws DefinitionsFactoryException if some error has occured when trying to get parent layout of page's layout layout
1172     */

1173    public static Set getIndexedFieldIdentifiers(String JavaDoc layoutDefinition, HttpServletRequest JavaDoc request) throws DefinitionsFactoryException {
1174        return getFieldIdentifiers(layoutDefinition, request, true);
1175    }
1176
1177    /**
1178     * Returns set of unindexed field identifiers
1179     *
1180     * @param layoutDefinition Definition of layout to search fields on (all parent layouts will also be searched)
1181     * @param request HttpServletRequest we are currently processing
1182     * @return Set of unindexed identifiers
1183     * @throws DefinitionsFactoryException if some error has occured when trying to get parent layout of page's layout layout
1184     */

1185    public static Set getUnIndexedFieldIdentifiers(String JavaDoc layoutDefinition, HttpServletRequest JavaDoc request) throws DefinitionsFactoryException {
1186        return getFieldIdentifiers(layoutDefinition, request, false);
1187    }
1188
1189
1190    /**
1191     * Returns set of fields' identifiers for layout with specified definition
1192     *
1193     * @param layoutDefinition Definition of layout to search fields on
1194     * @param request HttpServletRequest we are currently processing
1195     * @param indexed If true, indexed field identifiers will be returned, otherwise - unindexed
1196     * @return Set of identifiers
1197     * @throws DefinitionsFactoryException if some error has occured when trying to get parent layout of page's layout layout
1198     */

1199    protected static Set getFieldIdentifiers(String JavaDoc layoutDefinition, HttpServletRequest JavaDoc request, boolean indexed) throws DefinitionsFactoryException {
1200        ServletContext JavaDoc servletContext = request.getSession().getServletContext();
1201        ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
1202        LayoutManager layoutManager = (LayoutManager) applicationContext.getBean(Constants.LAYOUT_MANAGER_BEAN);
1203
1204        Set fieldIdentifiers = new HashSet();
1205
1206        do {
1207            Layout layout = layoutManager.findLayoutByDefinition(layoutDefinition);
1208            if ( layout != null ) {
1209                fieldIdentifiers.addAll(layout.getContentFieldsMap().keySet());
1210            }
1211            layoutDefinition = ((HeritableComponentDefinition) TilesUtil.getDefinition(layoutDefinition, request, servletContext)).getExtends();
1212        } while ( layoutDefinition != null );
1213
1214        Set identifiers = new HashSet();
1215        for ( Iterator i = fieldIdentifiers.iterator(); i.hasNext(); ) {
1216            String JavaDoc identifier = (String JavaDoc) i.next();
1217            int k = identifier.indexOf('[');
1218            if ( k != -1 ) {
1219                identifier = identifier.substring(0, k);
1220                if ( indexed ) {
1221                    identifiers.add(identifier);
1222                }
1223            } else {
1224                if ( !indexed ) {
1225                    identifiers.add(identifier);
1226                }
1227            }
1228        }
1229        return identifiers;
1230    }
1231
1232    /**
1233     * Checks charset for support
1234     *
1235     * @param charset to check
1236     * @return <code>true</code> if supported
1237     */

1238    public static boolean isCharsetSupported(String JavaDoc charset) {
1239        boolean result = false;
1240        try {
1241            result = Charset.isSupported(charset);
1242        } catch ( Exception JavaDoc e ) {
1243            //do nothing
1244
}
1245        return result;
1246    }
1247
1248    /**
1249     * Looks up for base object (in common case page or resource) with specified URI
1250     *
1251     * @param ref URI to lookup base object
1252     * @param servletContext Servlet context of our application
1253     * @param contextPath Application context path
1254     * @return Base object or <code>null</code> if none was found or URI is external
1255     */

1256    public static BaseObject lookupObject(String JavaDoc ref, ServletContext JavaDoc servletContext, String JavaDoc contextPath) {
1257        return lookupObject(ref, servletContext, contextPath, null);
1258    }
1259
1260    /**
1261     * Looks up for base object (in common case page or resource) with specified URI
1262     *
1263     * @param ref URI to lookup base object
1264     * @param servletContext Servlet context of our application
1265     * @param contextPath Application context path
1266     * @param request HTTP request which allows to determine whether given
1267     * ref is external (if <code>null</code>, the ref is
1268     * assumed to be internal)
1269     * @return Base object or <code>null</code> if none was found or URI is external
1270     */

1271    public static BaseObject lookupObject(String JavaDoc ref, ServletContext JavaDoc servletContext, String JavaDoc contextPath, HttpServletRequest JavaDoc request) {
1272
1273        if ( ref == null || ref.trim().length() == 0 ) {
1274            return null;
1275        }
1276
1277        if (request != null) {
1278            if (ref.toLowerCase().startsWith("http://") || ref.toLowerCase().startsWith("https://")) {
1279                if (isExternalURL(ref, request)) {
1280                    return null;
1281                }
1282            }
1283        }
1284
1285        BaseObject obj = null;
1286        String JavaDoc uri = new String JavaDoc(ref);
1287
1288        // check for scheme. it must be http or https, otherwise URI is external
1289
if ( uri.startsWith("http") ) {
1290            String JavaDoc scheme = null;
1291            if ( uri.startsWith("https") ) {
1292                scheme = "https://";
1293            } else {
1294                scheme = "http://";
1295            }
1296            uri = uri.substring(scheme.length());
1297
1298            // remove everything before next slash (typically host and, probably, port)
1299
int k = uri.indexOf("/");
1300            if ( k != -1 ) {
1301                uri = uri.substring(k);
1302            }
1303
1304        }
1305
1306        // remove context path
1307
if ( uri.startsWith(contextPath) && !contextPath.equals("/") ) {
1308            uri = uri.substring(contextPath.length());
1309        }
1310
1311        // add starting slash
1312
if ( !uri.startsWith("/") ) {
1313            uri = "/" + uri;
1314        }
1315
1316        // remove query string
1317
int k = uri.indexOf("?");
1318        if ( k != -1 ) {
1319            uri = uri.substring(0, k);
1320        }
1321
1322        ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
1323
1324        // now we can look up for object
1325
if ( uri.startsWith(Constants.RESOURCES_URI_PREFIX) ) {
1326            // look up for resource
1327
ContentResourceManager contentResourceManager = (ContentResourceManager) applicationContext.getBean(Constants.CONTENT_RESOURCE_MANAGER_BEAN);
1328            obj = contentResourceManager.findContentResourceByUri(uri);
1329        } else {
1330            // look up for page
1331

1332            // it may begin with /rw prefix, so cut it off (if it's not a news
1333
// item or testimonial, because they have their own prefixes)
1334
if (uri.startsWith(Constants.LOCALIZED_URI_PREFIX + "/")
1335                    && !uri.startsWith(NewsModuleWebConstants.NEWS_ITEM_URI_PREFIX)
1336                    && !uri.startsWith(TestimonialModuleWebConstants.TESTIMONIAL_URI_PREFIX)) {
1337                uri = uri.substring(Constants.LOCALIZED_URI_PREFIX.length());
1338            }
1339
1340            // remove extension
1341
k = uri.lastIndexOf(".");
1342            if ( k != -1 ) {
1343                uri = uri.substring(0, k);
1344            }
1345
1346            // check for locale suffix
1347
k = uri.lastIndexOf(".");
1348            if ( k != -1 && k == uri.length() - 3 ) {
1349                uri = uri.substring(0, k);
1350            }
1351
1352            PageManager pageManager = (PageManager) applicationContext.getBean(Constants.PAGE_MANAGER_BEAN);
1353            obj = pageManager.findPageByUri(uri);
1354        }
1355
1356        return obj;
1357    }
1358
1359    /**
1360     * Maps set of given references (URIs) to corresponding base objects (pages and/or resources).
1361     * If no object has been found, ref is ignored.
1362     *
1363     * @param refs Set of refs to lookup objects for
1364     * @param servletContext Servlet context of our application
1365     * @param contextPath Application context path
1366     * @return Map with pairs <code>ref -&gt; object</code>. Map can be empty if all references are external or point to
1367     * non-existing objects
1368     */

1369    public static Map mapObjectsToRefs(Set refs, ServletContext JavaDoc servletContext, String JavaDoc contextPath) {
1370        Map linkedObjects = new HashMap();
1371        for ( Iterator i = refs.iterator(); i.hasNext(); ) {
1372            String JavaDoc ref = (String JavaDoc) i.next();
1373            BaseObject linkedObject = lookupObject(ref, servletContext, contextPath);
1374            if ( linkedObject != null ) {
1375                linkedObjects.put(ref, linkedObject);
1376            }
1377        }
1378        return linkedObjects;
1379    }
1380
1381    /**
1382     * Returns <code>true</code> if user has at least one role (if <code>all</code> is <code>false</code>)
1383     * or all roles (if <code>all</code> is <code>true</code>), specified in collection
1384     *
1385     * @param roles Roles to check
1386     * @param all Whether or not user must have all roles, specified in collection
1387     * @param property Property of bean in list to get role name
1388     * @param request HTTP servlet request we're currently proceeding
1389     * @return <code>True</code> if user has role, <code>false</code> otherwise.
1390     */

1391    public static boolean isUserInRole(Collection roles, boolean all, String JavaDoc property, HttpServletRequest JavaDoc request) throws IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
1392        boolean isUserInRole = all;
1393        if ( roles != null && !roles.isEmpty() ) {
1394            Iterator rolesIterator = roles.iterator();
1395            while ( rolesIterator.hasNext() ) {
1396                Object JavaDoc bean = rolesIterator.next();
1397                if ( bean == null ) {
1398                    continue;
1399                }
1400                String JavaDoc roleName = null;
1401                if ( bean instanceof String JavaDoc ) {
1402                    roleName = (String JavaDoc) bean;
1403                } else if ( property != null && property.trim().length() > 0 ) {
1404                    roleName = String.valueOf(PropertyUtils.getProperty(bean, property));
1405                } else {
1406                    roleName = String.valueOf(bean);
1407                }
1408                boolean roleCheck = request.isUserInRole(roleName.trim());
1409                if ( all ) {
1410                    isUserInRole = isUserInRole && roleCheck;
1411                } else {
1412                    isUserInRole = isUserInRole || roleCheck;
1413                }
1414            }
1415        } else {
1416            // if no role is specified, grant access
1417
isUserInRole = true;
1418        }
1419        return isUserInRole;
1420    }
1421
1422    /**
1423     * Returns <code>true</code> if user has at least one role (if <code>all</code> is <code>false</code>)
1424     * or all roles (if <code>all</code> is <code>true</code>), specified in collection
1425     *
1426     * @param roles Roles to check
1427     * @param all Whether or not user must have all roles, specified in collection
1428     * @param request HTTP servlet request we're currently proceeding
1429     * @return <code>True</code> if user has role, <code>false</code> otherwise.
1430     */

1431    public static boolean isUserInRole(Collection roles, boolean all, HttpServletRequest JavaDoc request) {
1432        boolean isUserInRole = false;
1433        try {
1434            isUserInRole = isUserInRole(roles, all, null, request);
1435        } catch ( Exception JavaDoc ex ) {
1436            // do nothing
1437
}
1438        return isUserInRole;
1439    }
1440
1441    /**
1442     * Returns array of role names which are granted to gain access to action page with specified URI
1443     *
1444     * @param uri URI of action page to lookup role names for
1445     * @param request HTTP servlet request we're currently proceeding
1446     * @return Array of role names
1447     */

1448    public static String JavaDoc[] getAPRoleNames(String JavaDoc uri, HttpServletRequest JavaDoc request) {
1449        ModuleConfig moduleConfig = ModuleUtils.getInstance().getModuleConfig(request, request.getSession().getServletContext());
1450        ActionMapping mapping = (ActionMapping) moduleConfig.findActionConfig(uri);
1451        if ( mapping == null ) {
1452            return null;
1453        } else {
1454            return mapping.getRoleNames();
1455        }
1456    }
1457
1458    /**
1459     * Returns list of role names which are granted to gain access to action page with specified URI
1460     *
1461     * @param uri URI of action page to lookup role names for
1462     * @param request HTTP servlet request we're currently proceeding
1463     * @return List of role names
1464     */

1465    public static List getAPRoleNamesAsList(String JavaDoc uri, HttpServletRequest JavaDoc request) {
1466        String JavaDoc[] roles = getAPRoleNames(uri, request);
1467        if ( roles == null ) {
1468            return null;
1469        } else {
1470            return Arrays.asList(roles);
1471        }
1472    }
1473
1474    /**
1475     * Returns <code>true</code> if specified URL is absolute and
1476     * <code>false</code> otherwise.
1477     * Absolute URL is the URL which starts with the scheme, colon sign and sequence of two slashes
1478     *
1479     * @param url URL to check
1480     * @return <code>true</code> if specified URL is absolute and <code>false</code> otherwise.
1481     */

1482    public static boolean isAbsoluteURL(String JavaDoc url) {
1483        // a null URL is not absolute
1484
if ( url == null ) {
1485            return false;
1486        }
1487
1488        // valid scheme starts from a sequence of valid scheme chars, colon sign and sequence of two slashes
1489
int colonPos = url.indexOf(":");
1490        if ( colonPos != -1 && url.startsWith("//", colonPos + 1) ) {
1491            // colon sign exists in string, such as sequence of two slashes
1492
// check sequence of characters before colon to be the valid scheme
1493
String JavaDoc scheme = url.substring(0, colonPos);
1494            return isValidScheme(scheme);
1495        } else {
1496            return false;
1497        }
1498
1499    }
1500
1501    /**
1502     * Returns <code>true</code> if URL is external and <code>false</code> otherwise.<br />
1503     * URL is external if any of the following conditions are met:
1504     * <ul>
1505     * <li>URL is not absolute and does not start with the slash</li>
1506     * <li>URL is absolute and host name does not equal to the host name of server, we're running on</li>
1507     * <li>URL is absolute and our port number is not standard (is not 80 nor 443) and is not present in URL</li>
1508     * <li>URL is absolute and context path of our application is not present in URL</li>
1509     * </ul>
1510     *
1511     * @param url URL to check
1512     * @param request HTTP Servlet request we're currently proceeding
1513     * @return <code>true</code> if URL is external and <code>false</code> otherwise
1514     */

1515    public static boolean isExternalURL(String JavaDoc url, HttpServletRequest JavaDoc request) {
1516
1517        String JavaDoc temp = new String JavaDoc(url);
1518
1519        // get our host
1520
String JavaDoc host = request.getServerName();
1521        boolean urlIsAbsolute = isAbsoluteURL(url);
1522
1523        if ( urlIsAbsolute ) {
1524
1525            // remove scheme and sequence of two slashes from the start of the string
1526
int schemeEnd = url.indexOf("//");
1527
1528            // because uri is absolute, schemeEnd cannot be -1
1529
temp = url.substring(schemeEnd + 2);
1530
1531            boolean isHttps;
1532            String JavaDoc scheme = url.substring(0, schemeEnd);
1533            isHttps = "https:".equalsIgnoreCase(scheme);
1534            if (!isHttps) {
1535                if (!"http:".equalsIgnoreCase(scheme)) {
1536                    // unknown scheme, URL is external
1537
return true;
1538                }
1539            }
1540
1541            int firstSlash = temp.indexOf("/");
1542            if (firstSlash == -1) {
1543                firstSlash = temp.length();
1544            }
1545            int firstColon = temp.indexOf(":");
1546            if (firstColon == -1) {
1547                firstColon = temp.length();
1548            }
1549            int firstNonHostChar = firstColon < firstSlash ? firstColon : firstSlash;
1550            if ( !temp.substring(0, firstNonHostChar).equals(host) ) {
1551                return true;
1552            }
1553            // host is the same, check port
1554
ServletContext JavaDoc servletContext = request.getSession().getServletContext();
1555            String JavaDoc portStr = isHttps
1556                             ? servletContext.getInitParameter(SslUtil.HTTPS_PORT_PARAM)
1557                             : servletContext.getInitParameter(SslUtil.HTTP_PORT_PARAM);
1558            int port = Integer.valueOf(portStr).intValue();
1559            // port is custom if it is not equal to 80 for HTTP nor to 443 for HTTPS
1560
boolean standardPort = !isHttps ? (port == 80) : (port == 443);
1561            temp = temp.substring(host.length());
1562            if ( temp.startsWith(":") ) {
1563                temp = temp.substring(1);
1564                if ( !temp.startsWith(portStr) ) {
1565                    return true;
1566                }
1567                temp = temp.substring(portStr.length());
1568            } else if ( !standardPort ) {
1569                return true;
1570            }
1571
1572            // port test passed, check context path
1573
String JavaDoc contextPath = request.getContextPath();
1574            if ( !temp.startsWith(contextPath) ) {
1575                return true;
1576            } else {
1577                // all tests have been passed. uri is internal
1578
return false;
1579            }
1580        } else {
1581            // URL is not absolute, so search for slash at the beginning
1582
return !url.startsWith("/");
1583        }
1584    }
1585
1586    /**
1587     * Determines if the character is allowed in the scheme of an URI.
1588     * RFC 2396 "Uniform Resource Identifiers: Generic Syntax" says the following (Section 3.1 "Scheme Component"):
1589     * <blockquote>
1590     * Scheme names consist of a sequence of characters beginning with a
1591     * lower case letter and followed by any combination of lower case
1592     * letters, digits, plus ("+"), period ("."), or hyphen ("-"). For
1593     * resiliency, programs interpreting URI should treat upper case letters
1594     * as equivalent to lower case in scheme names (e.g., allow "HTTP" as
1595     * well as "http").
1596     * <p/>
1597     * </blockquote>
1598     */

1599    protected static boolean isValidSchemeChar(char c) {
1600        return Character.isLetterOrDigit(c) || c == '+' || c == '-' || c == '.';
1601    }
1602
1603    /**
1604     * Checks given scheme for validity.
1605     * RFC 2396 "Uniform Resource Identifiers: Generic Syntax" says the following (Section 3.1 "Scheme Component"):
1606     * <blockquote>
1607     * Scheme names consist of a sequence of characters beginning with a
1608     * lower case letter and followed by any combination of lower case
1609     * letters, digits, plus ("+"), period ("."), or hyphen ("-"). For
1610     * resiliency, programs interpreting URI should treat upper case letters
1611     * as equivalent to lower case in scheme names (e.g., allow "HTTP" as
1612     * well as "http").
1613     * <p/>
1614     * </blockquote>
1615     *
1616     * @param scheme Scheme to check for validity
1617     * @return <code>true</code> if scheme is valid and <code>false</code> otherwise
1618     */

1619    protected static boolean isValidScheme(String JavaDoc scheme) {
1620
1621        // if scheme is null, return true
1622
if ( scheme == null ) {
1623            return true;
1624        }
1625
1626        if ( Character.isLetter(scheme.charAt(0)) ) {
1627            // check all other characters to be valid scheme chars
1628
for ( int i = 1; i < scheme.length(); i++ ) {
1629                if ( !isValidSchemeChar(scheme.charAt(i)) ) {
1630                    return false;
1631                }
1632            }
1633        } else {
1634            return false;
1635        }
1636
1637        return true;
1638    }
1639
1640}
1641
Popular Tags