001 // Copyright 2006, 2008, 2010, 2012 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.internal.services;
016
017 import org.apache.tapestry5.ioc.Resource;
018 import org.apache.tapestry5.ioc.internal.util.AbstractResource;
019 import org.apache.tapestry5.services.Context;
020
021 import java.io.File;
022 import java.net.MalformedURLException;
023 import java.net.URL;
024
025 /**
026 * A resource stored with in the web application context.
027 */
028 public class ContextResource extends AbstractResource
029 {
030 private static final int PRIME = 37;
031
032 private final Context context;
033
034 // Guarded by lock
035 private URL url;
036
037 // Guarded by lock
038 private boolean urlResolved;
039
040 public ContextResource(Context context, String path)
041 {
042 super(path);
043
044 assert context != null;
045
046 this.context = context;
047 }
048
049 @Override
050 public String toString()
051 {
052 return String.format("context:%s", getPath());
053 }
054
055 @Override
056 protected Resource newResource(String path)
057 {
058 return new ContextResource(context, path);
059 }
060
061 public URL toURL()
062 {
063 try
064 {
065 acquireReadLock();
066 if (!urlResolved)
067 {
068 resolveURL();
069 }
070
071 return url;
072
073 } finally
074 {
075 releaseReadLock();
076 }
077 }
078
079 private void resolveURL()
080 {
081 try
082 {
083 upgradeReadLockToWriteLock();
084
085 // Race condition on the write lock:
086 if (urlResolved)
087 {
088 return;
089 }
090
091 // This is so easy to screw up; ClassLoader.getResource() doesn't want a leading slash,
092 // and HttpServletContext.getResource() does. This is what I mean when I say that
093 // a framework is an accumulation of the combined experience of many users and developers.
094
095 String contextPath = "/" + getPath();
096
097 // Always prefer the actual file to the URL. This is critical for templates to
098 // reload inside Tomcat.
099
100 File file = context.getRealFile(contextPath);
101
102 if (file != null && file.exists())
103 {
104 try
105 {
106 url = file.toURI().toURL();
107 urlResolved = true;
108 return;
109 } catch (MalformedURLException ex)
110 {
111 throw new RuntimeException(ex);
112 }
113 }
114
115 // But, when packaged inside a WAR or JAR, the File will not be available, so use whatever
116 // URL we get ... but reloading won't work.
117
118 url = context.getResource(contextPath);
119 urlResolved = true;
120
121 } finally
122 {
123 downgradeWriteLockToReadLock();
124 }
125 }
126
127 @Override
128 public int hashCode()
129 {
130 return PRIME * context.hashCode() + getPath().hashCode();
131 }
132
133 @Override
134 public boolean equals(Object obj)
135 {
136 if (this == obj) return true;
137 if (obj == null) return false;
138 if (getClass() != obj.getClass()) return false;
139
140 final ContextResource other = (ContextResource) obj;
141
142 return context == other.context && getPath().equals(other.getPath());
143 }
144
145 }