1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.example.demo;
21
22 import org.apache.commons.io.IOUtils;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import javax.annotation.PostConstruct;
27 import javax.enterprise.context.ApplicationScoped;
28 import javax.enterprise.event.Event;
29 import javax.faces.context.ExternalContext;
30 import javax.faces.context.FacesContext;
31 import javax.inject.Inject;
32 import javax.inject.Named;
33 import javax.servlet.ServletContext;
34 import java.io.File;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.Serializable;
38 import java.lang.invoke.MethodHandles;
39 import java.nio.charset.StandardCharsets;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.Enumeration;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Set;
47 import java.util.regex.Pattern;
48 import java.util.zip.ZipEntry;
49 import java.util.zip.ZipException;
50 import java.util.zip.ZipFile;
51
52 @ApplicationScoped
53 @Named
54 public class NavigationTree implements Serializable {
55
56 private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
57
58 private NavigationNode root;
59
60 @Inject
61 private Event<NavigationNode> events;
62
63
64
65
66
67
68 public NavigationTree() {
69 LOG.info("<init> " + this);
70 }
71
72 @PostConstruct
73 protected void postConstruct() {
74
75 final ServletContext servletContext;
76 servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
77
78 final List<NavigationNode> nodes = new ArrayList<>();
79
80 final List<String> listWar = locateResourcesInWar(servletContext, "/content", new ArrayList<>());
81 addToResult(listWar, nodes);
82
83
84 final List<String> listClasspath = getResourcesFromClasspath();
85 addToResult(listClasspath, nodes);
86
87 Collections.sort(nodes);
88
89
90 root = nodes.get(0);
91
92 final Map<String, NavigationNode> map = new HashMap<>();
93
94 for (final NavigationNode node : nodes) {
95
96 map.put(node.getBranch(), node);
97 final String parent = node.getBranch().substring(0, node.getBranch().lastIndexOf('/'));
98 if (!parent.equals("")) {
99 map.get(parent).add(node);
100 }
101 node.evaluateTreePath();
102 }
103 }
104
105 private void addToResult(List<String> listWar, List<NavigationNode> nodes) {
106 for (final String path : listWar) {
107 if (path.contains("/x-") || !path.contains(".xhtml")) {
108
109 continue;
110 }
111 nodes.add(new NavigationNode(path, this));
112 }
113 }
114
115 protected List<String> locateResourcesInWar(
116 final ServletContext servletContext, final String directory, final List<String> result) {
117
118 final Set<String> resourcePaths = servletContext.getResourcePaths(directory);
119
120 if (resourcePaths != null) {
121 for (final String resourcePath : resourcePaths) {
122
123 final String path = resourcePath.substring(resourcePath.indexOf("/content"));
124
125 if (path.endsWith("/")
126 || path.lastIndexOf('.') < path.lastIndexOf('/')) {
127 locateResourcesInWar(servletContext, path.substring(path.indexOf("/content")), result);
128 continue;
129 }
130
131 result.add(path);
132 }
133 }
134 return result;
135 }
136
137 public NavigationNode findByViewId(final String viewId) {
138 if (viewId != null) {
139 final Enumeration enumeration = root.depthFirstEnumeration();
140 while (enumeration.hasMoreElements()) {
141 final NavigationNode node = (NavigationNode) enumeration.nextElement();
142 if (node.getOutcome() != null && viewId.contains(node.getOutcome())) {
143 return node;
144 }
145 }
146 }
147 return null;
148 }
149
150 public NavigationNode getTree() {
151 return root;
152 }
153
154 public void gotoNode(final NavigationNode node) {
155 if (node != null) {
156 events.fire(node);
157 } else {
158 events.fire(root);
159 }
160 }
161
162 public String getSource() {
163 final FacesContext facesContext = FacesContext.getCurrentInstance();
164 final ExternalContext externalContext = facesContext.getExternalContext();
165 final String viewId = facesContext.getViewRoot().getViewId();
166 try (final InputStream resourceAsStream = externalContext.getResourceAsStream(viewId)) {
167 return IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
168 } catch (final IOException e) {
169 LOG.error("", e);
170 return "error";
171 }
172 }
173
174 private List<String> getResourcesFromClasspath() {
175 Pattern pattern = Pattern.compile(".*/content/.*\\.xhtml");
176 final ArrayList<String> result = new ArrayList<>();
177 final String classPath = System.getProperty("java.class.path", ".");
178 final String[] classPathElements = classPath.split(System.getProperty("path.separator"));
179 for (final String element : classPathElements) {
180 result.addAll(getResourcesFromClasspath(element, pattern, "/content/"));
181 }
182 return result;
183 }
184
185 private List<String> getResourcesFromClasspath(final String element, final Pattern pattern, final String base) {
186 final ArrayList<String> result = new ArrayList<>();
187 final File file = new File(element);
188 if (file.isDirectory()) {
189 result.addAll(getResourcesFromDirectory(file, pattern, base));
190 } else {
191 result.addAll(getResourcesFromJarFile(file, pattern, base));
192 }
193 return result;
194 }
195
196 private List<String> getResourcesFromJarFile(final File file, final Pattern pattern, final String base) {
197 final ArrayList<String> result = new ArrayList<>();
198 ZipFile zip;
199 try {
200 zip = new ZipFile(file);
201 } catch (final ZipException e) {
202 throw new Error(e);
203 } catch (final IOException e) {
204 throw new Error(e);
205 }
206 final Enumeration e = zip.entries();
207 while (e.hasMoreElements()) {
208 final ZipEntry ze = (ZipEntry) e.nextElement();
209 final String fileName = ze.getName();
210 final boolean accept = pattern.matcher(fileName).matches();
211 if (accept) {
212 result.add(fileName.substring(fileName.indexOf(base)));
213 }
214 }
215 try {
216 zip.close();
217 } catch (final IOException e1) {
218 throw new Error(e1);
219 }
220 return result;
221 }
222
223 private List<String> getResourcesFromDirectory(final File directory, final Pattern pattern, final String base) {
224 final ArrayList<String> result = new ArrayList<String>();
225 final File[] fileList = directory.listFiles();
226 for (final File file : fileList) {
227 if (file.isDirectory()) {
228 result.addAll(getResourcesFromDirectory(file, pattern, base));
229 } else {
230 try {
231 final String fileName = file.getCanonicalPath();
232 final boolean accept = pattern.matcher(fileName).matches();
233 if (accept) {
234 result.add(fileName.substring(fileName.indexOf(base)));
235 }
236 } catch (final IOException e) {
237 throw new Error(e);
238 }
239 }
240 }
241 return result;
242 }
243 }