1 package net.sf.tacos.rest;
2
3 import java.net.URL;
4 import java.net.MalformedURLException;
5 import java.io.File;
6 import java.io.IOException;
7 import java.util.Set;
8 import java.util.Map;
9 import javax.servlet.http.HttpServlet;
10 import javax.servlet.ServletContext;
11
12 import org.apache.tapestry.INamespace;
13 import org.apache.tapestry.Tapestry;
14 import org.apache.tapestry.engine.ServiceEncoder;
15 import org.apache.tapestry.engine.ServiceEncoding;
16 import org.apache.tapestry.services.ServiceConstants;
17 import org.apache.tapestry.services.ApplicationInitializer;
18 import org.apache.commons.collections.FastHashMap;
19
20 import org.scannotation.AnnotationDB;
21
22
23
24
25
26
27
28
29 public class RestPageEncoder implements ServiceEncoder, ApplicationInitializer {
30
31 private String url;
32 private boolean caseSensitive;
33
34 private Map<String, String> pathToPageMap;
35 private Map<String, String> pageToPathMap;
36
37 public void encode(ServiceEncoding encoding) {
38 String service = encoding.getParameterValue(ServiceConstants.SERVICE);
39
40 if (!service.equals(Tapestry.PAGE_SERVICE)) {
41 return;
42 }
43
44 String pageName = encoding.getParameterValue(ServiceConstants.PAGE);
45
46
47 if (pageName.indexOf(INamespace.SEPARATOR) >= 0) {
48 return;
49 }
50
51 StringBuffer buffer = new StringBuffer(url);
52 buffer.append('/');
53 String pathOverride = pageToPathMap.get(pageName);
54 if (pathOverride != null) {
55 buffer.append(pathOverride);
56 } else {
57 buffer.append(pageName);
58 }
59
60 encoding.setServletPath(buffer.toString());
61 encoding.setParameterValue(ServiceConstants.SERVICE, null);
62 encoding.setParameterValue(ServiceConstants.PAGE, null);
63 }
64
65 public void decode(ServiceEncoding encoding) {
66 String servletPath = encoding.getServletPath();
67
68 if (!servletPath.startsWith(url)) {
69 return;
70 }
71
72
73 if (encoding.getPathInfo()==null) {
74 return;
75 }
76
77
78 String page = encoding.getPathInfo().substring(1);
79
80 String pageOverride = caseSensitive ?
81 pathToPageMap.get(page) : pathToPageMap.get(page.toLowerCase());
82 if (pageOverride != null) {
83 page = pageOverride;
84 }
85
86 encoding.setParameterValue(ServiceConstants.SERVICE, Tapestry.PAGE_SERVICE);
87 encoding.setParameterValue(ServiceConstants.PAGE, page);
88 }
89
90 public void setUrl(String url) {
91 this.url = url;
92 }
93
94 public void setCaseSensitive(boolean caseSensitive) {
95 this.caseSensitive = caseSensitive;
96 }
97
98 public void initialize(HttpServlet servlet) {
99 FastHashMap pageToPath = new FastHashMap();
100 FastHashMap pathToPage = new FastHashMap();
101
102 URL webInfClasses = findWebInfClassesPath(servlet.getServletContext());
103
104 scan(pageToPath, pathToPage, webInfClasses);
105
106 storeMaps(pageToPath, pathToPage);
107 }
108
109 private void scan(FastHashMap pageToPath, FastHashMap pathToPage, URL url) {
110 if (url == null)
111 return;
112
113 AnnotationDB db = new AnnotationDB();
114 db.addIgnoredPackages("org");
115 try {
116 db.scanArchives(url);
117 } catch (IOException e) {
118 return;
119 }
120
121 Set<String> simpleClasses = db.getAnnotationIndex().get(UriTemplate.class.getName());
122 if (simpleClasses == null)
123 return;
124
125 for (String simpleClass : simpleClasses) {
126 UriTemplate uriTemplate;
127 try {
128 uriTemplate = Class.forName(simpleClass).getAnnotation(UriTemplate.class);
129 } catch (ClassNotFoundException e) {
130 continue;
131 }
132
133 String path = uriTemplate.value();
134 if (path.startsWith("/")) {
135 path = path.substring(1);
136 }
137 if (!caseSensitive) {
138 path = path.toLowerCase();
139 }
140
141 String page = toPage(simpleClass);
142 pathToPage.put(path, page);
143 pageToPath.put(page, path);
144
145
146 for (String aliasPath : uriTemplate.alias()) {
147 pathToPage.put(aliasPath, page);
148 }
149
150 }
151 }
152
153 @SuppressWarnings("unchecked")
154 private void storeMaps(FastHashMap pageToPath, FastHashMap pathToPage) {
155 pageToPath.setFast(true);
156 pathToPage.setFast(true);
157 pageToPathMap = pageToPath;
158 pathToPageMap = pathToPage;
159 }
160
161
162
163
164
165
166
167 private String toPage(String className) {
168 int pos = className.indexOf(".pages.");
169 return className.substring(pos + 7).replace('.', '/');
170 }
171
172 private URL findWebInfClassesPath(ServletContext servletContext) {
173 String path = servletContext.getRealPath("/WEB-INF/classes");
174 if (path == null) return null;
175 File fp = new File(path);
176 if (!fp.exists()) return null;
177 try {
178 return fp.toURI().toURL();
179 }
180 catch (MalformedURLException e) {
181 throw new RuntimeException(e);
182 }
183 }
184 }