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 }