View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.view.facelets.impl;
20  
21  import java.io.IOException;
22  import java.net.URL;
23  import java.net.URLConnection;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import javax.faces.view.facelets.FaceletCache;
28  import javax.faces.view.facelets.FaceletException;
29  
30  import org.apache.myfaces.shared.resource.ResourceLoaderUtils;
31  import org.apache.myfaces.view.facelets.util.ParameterCheck;
32  
33  /**
34   * TODO: Note MyFaces core has another type of Facelet for read composite component
35   * metadata. The reason behind do this in MyFaces is to retrieve some information
36   * related to insertChildren/insertFacet that can be used as metadata and use that
37   * information later to do the hack for composite components using templates, instead
38   * rely on component relocation. This is not handled by FaceletCache included here 
39   * but in practice this should not be a problem, because the intention of this class
40   * is handle Facelet instances created using custom ResourceResolver stuff, and 
41   * usually those pages are for views, not for composite components. Even if that is
42   * true, composite component metadata Facelet is smaller (only add cc:xxx stuff) that
43   * the other ones used for views or the one used to apply the composite component
44   * itself.  
45   * 
46   * @author Leonardo Uribe
47   * @since 2.1.0
48   *
49   */
50  class FaceletCacheImpl extends FaceletCache<DefaultFacelet>
51  {
52  
53      private static final long INFINITE_DELAY = -1;
54      private static final long NO_CACHE_DELAY = 0;
55      
56      private Map<String, DefaultFacelet> _facelets;
57      
58      private Map<String, DefaultFacelet> _viewMetadataFacelets;
59  
60      private long _refreshPeriod;
61      
62      FaceletCacheImpl(long refreshPeriod)
63      {
64          _refreshPeriod = refreshPeriod < 0 ? INFINITE_DELAY : refreshPeriod * 1000;
65          
66          _facelets = new HashMap<String, DefaultFacelet>();
67          
68          _viewMetadataFacelets = new HashMap<String, DefaultFacelet>();
69      }
70  
71      @Override
72      public DefaultFacelet getFacelet(URL url) throws IOException
73      {
74          ParameterCheck.notNull("url", url);
75          
76          String key = url.toString();
77          
78          DefaultFacelet f = _facelets.get(key);
79          
80          if (f == null || this.needsToBeRefreshed(f))
81          {
82              //f = this._createFacelet(url);
83              f = getMemberFactory().newInstance(url);
84              if (_refreshPeriod != NO_CACHE_DELAY)
85              {
86                  Map<String, DefaultFacelet> newLoc = new HashMap<String, DefaultFacelet>(_facelets);
87                  newLoc.put(key, f);
88                  _facelets = newLoc;
89              }
90          }
91          
92          return f;
93      }
94      
95      @Override
96      public boolean isFaceletCached(URL url)
97      {
98          return _facelets.containsKey(url);
99      }
100 
101     @Override
102     public DefaultFacelet getViewMetadataFacelet(URL url) throws IOException
103     {
104         ParameterCheck.notNull("url", url);
105         
106         String key = url.toString();
107         
108         DefaultFacelet f = _viewMetadataFacelets.get(key);
109         
110         if (f == null || this.needsToBeRefreshed(f))
111         {
112             //f = this._createViewMetadataFacelet(url);
113             f = getMetadataMemberFactory().newInstance(url);
114             if (_refreshPeriod != NO_CACHE_DELAY)
115             {
116                 Map<String, DefaultFacelet> newLoc = new HashMap<String, DefaultFacelet>(_viewMetadataFacelets);
117                 newLoc.put(key, f);
118                 _viewMetadataFacelets = newLoc;
119             }
120         }
121         
122         return f;
123     }
124 
125     @Override
126     public boolean isViewMetadataFaceletCached(URL url)
127     {
128         return _viewMetadataFacelets.containsKey(url);
129     }
130 
131     /**
132      * Template method for determining if the Facelet needs to be refreshed.
133      * 
134      * @param facelet
135      *            Facelet that could have expired
136      * @return true if it needs to be refreshed
137      */
138     protected boolean needsToBeRefreshed(DefaultFacelet facelet)
139     {
140         // if set to 0, constantly reload-- nocache
141         if (_refreshPeriod == NO_CACHE_DELAY)
142         {
143             return true;
144         }
145 
146         // if set to -1, never reload
147         if (_refreshPeriod == INFINITE_DELAY)
148         {
149             return false;
150         }
151 
152         long target = facelet.getCreateTime() + _refreshPeriod;
153         if (System.currentTimeMillis() > target)
154         {
155             // Should check for file modification
156 
157             try
158             {
159                 URLConnection conn = facelet.getSource().openConnection();
160                 long lastModified = ResourceLoaderUtils.getResourceLastModified(conn);
161 
162                 return lastModified == 0 || lastModified > target;
163             }
164             catch (IOException e)
165             {
166                 throw new FaceletException("Error Checking Last Modified for " + facelet.getAlias(), e);
167             }
168         }
169 
170         return false;
171     }
172 }