1 /*
2  * Copyright (c) 2008-2019 Emmanuel Dupuy.
3  * This project is distributed under the GPLv3 license.
4  * This is a Copyleft license that gives the user the right to use,
5  * copy and modify the code freely for non-commercial purposes.
6  */
7 
8 package org.jd.gui.view.component;
9 
10 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
11 import org.jd.gui.api.API;
12 import org.jd.gui.api.feature.IndexesChangeListener;
13 import org.jd.gui.api.feature.UriGettable;
14 import org.jd.gui.api.model.Container;
15 import org.jd.gui.api.model.Indexes;
16 import org.jd.gui.util.exception.ExceptionUtil;
17 import org.jd.gui.util.index.IndexesUtil;
18 import org.jd.gui.util.io.TextReader;
19 import org.jd.gui.util.xml.AbstractXmlPathFinder;
20 
21 import java.awt.*;
22 import java.net.URI;
23 import java.net.URISyntaxException;
24 import java.util.*;
25 import java.util.List;
26 import java.util.concurrent.Future;
27 
28 public class WebXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
29     protected API api;
30     protected Container.Entry entry;
31     protected Collection<Future<Indexes>> collectionOfFutureIndexes;
32 
WebXmlFilePage(API api, Container.Entry entry)33     public WebXmlFilePage(API api, Container.Entry entry) {
34         this.api = api;
35         this.entry = entry;
36         // Load content file
37         String text = TextReader.getText(entry.getInputStream());
38         // Create hyperlinks
39         new PathFinder().find(text);
40         // Display
41         setText(text);
42     }
43 
getSyntaxStyle()44     public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_XML; }
45 
isHyperlinkEnabled(HyperlinkData hyperlinkData)46     protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { return ((TypeHyperlinkData)hyperlinkData).enabled; }
47 
openHyperlink(int x, int y, HyperlinkData hyperlinkData)48     protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) {
49         TypeHyperlinkData data = (TypeHyperlinkData)hyperlinkData;
50 
51         if (data.enabled) {
52             try {
53                 // Save current position in history
54                 Point location = textArea.getLocationOnScreen();
55                 int offset = textArea.viewToModel(new Point(x-location.x, y-location.y));
56                 URI uri = entry.getUri();
57                 api.addURI(new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), "position=" + offset, null));
58 
59                 // Open link
60                 if (hyperlinkData instanceof PathHyperlinkData) {
61                     PathHyperlinkData d = (PathHyperlinkData)hyperlinkData;
62                     String path = d.path;
63                     Container.Entry entry = searchEntry(this.entry.getContainer().getRoot(), path);
64                     if (entry != null) {
65                         api.openURI(x, y, Collections.singletonList(entry), null, path);
66                     }
67                 } else {
68                     String internalTypeName = data.internalTypeName;
69                     List<Container.Entry> entries = IndexesUtil.findInternalTypeName(collectionOfFutureIndexes, internalTypeName);
70                     String rootUri = entry.getContainer().getRoot().getUri().toString();
71                     ArrayList<Container.Entry> sameContainerEntries = new ArrayList<>();
72 
73                     for (Container.Entry entry : entries) {
74                         if (entry.getUri().toString().startsWith(rootUri)) {
75                             sameContainerEntries.add(entry);
76                         }
77                     }
78 
79                     if (sameContainerEntries.size() > 0) {
80                         api.openURI(x, y, sameContainerEntries, null, data.internalTypeName);
81                     } else if (entries.size() > 0) {
82                         api.openURI(x, y, entries, null, data.internalTypeName);
83                     }
84                 }
85             } catch (URISyntaxException e) {
86                 assert ExceptionUtil.printStackTrace(e);
87             }
88         }
89     }
90 
searchEntry(Container.Entry parent, String path)91     public static Container.Entry searchEntry(Container.Entry parent, String path) {
92         if (path.charAt(0) == '/')
93             path = path.substring(1);
94         return recursiveSearchEntry(parent, path);
95     }
96 
recursiveSearchEntry(Container.Entry parent, String path)97     public static Container.Entry recursiveSearchEntry(Container.Entry parent, String path) {
98         Container.Entry entry = null;
99 
100         for (Container.Entry child : parent.getChildren()) {
101             if (path.equals(child.getPath())) {
102                 entry = child;
103                 break;
104             }
105         }
106 
107         if (entry != null) {
108             return entry;
109         } else {
110             for (Container.Entry child : parent.getChildren()) {
111                 if (path.startsWith(child.getPath() + '/')) {
112                     entry = child;
113                     break;
114                 }
115             }
116 
117             return (entry != null) ? searchEntry(entry, path) : null;
118         }
119     }
120 
121     // --- UriGettable --- //
getUri()122     public URI getUri() { return entry.getUri(); }
123 
124     // --- ContentSavable --- //
getFileName()125     public String getFileName() {
126         String path = entry.getPath();
127         int index = path.lastIndexOf('/');
128         return path.substring(index+1);
129     }
130 
131     // --- IndexesChangeListener --- //
indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes)132     public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
133         // Update the list of containers
134         this.collectionOfFutureIndexes = collectionOfFutureIndexes;
135         // Refresh links
136         boolean refresh = false;
137 
138         for (Map.Entry<Integer, HyperlinkData> entry : hyperlinks.entrySet()) {
139             TypeHyperlinkData data = (TypeHyperlinkData)entry.getValue();
140             boolean enabled;
141 
142             if (data instanceof PathHyperlinkData) {
143                 PathHyperlinkData d = (PathHyperlinkData)data;
144                 enabled = searchEntry(this.entry.getContainer().getRoot(), d.path) != null;
145             } else {
146                 String internalTypeName = data.internalTypeName;
147                 enabled = IndexesUtil.containsInternalTypeName(collectionOfFutureIndexes, internalTypeName);
148             }
149 
150             if (data.enabled != enabled) {
151                 data.enabled = enabled;
152                 refresh = true;
153             }
154         }
155 
156         if (refresh) {
157             textArea.repaint();
158         }
159     }
160 
161     public static class PathHyperlinkData extends TypeHyperlinkData {
162         public boolean enabled;
163         public String path;
164 
PathHyperlinkData(int startPosition, int endPosition, String path)165         PathHyperlinkData(int startPosition, int endPosition, String path) {
166             super(startPosition, endPosition, null);
167             this.enabled = false;
168             this.path = path;
169         }
170     }
171 
172     protected static List<String> typeHyperlinkPaths = Arrays.asList(
173         "web-app/filter/filter-class",
174         "web-app/listener/listener-class",
175         "web-app/servlet/servlet-class");
176 
177     protected static List<String> pathHyperlinkPaths = Arrays.asList(
178         "web-app/jsp-config/taglib/taglib-location",
179         "web-app/welcome-file-list/welcome-file",
180         "web-app/login-config/form-login-config/form-login-page",
181         "web-app/login-config/form-login-config/form-error-page",
182         "web-app/jsp-config/jsp-property-group/include-prelude",
183         "web-app/jsp-config/jsp-property-group/include-coda");
184 
185     protected static List<String> hyperlinkPaths = new ArrayList<>(typeHyperlinkPaths.size() + pathHyperlinkPaths.size());
186 
187     static {
188         hyperlinkPaths.addAll(typeHyperlinkPaths);
189         hyperlinkPaths.addAll(pathHyperlinkPaths);
190     }
191 
192     public class PathFinder extends AbstractXmlPathFinder {
PathFinder()193         public PathFinder() {
194             super(hyperlinkPaths);
195         }
196 
handle(String path, String text, int position)197         public void handle(String path, String text, int position) {
198             String trim = text.trim();
199             if (trim != null) {
200                 int startIndex = position + text.indexOf(trim);
201                 int endIndex = startIndex + trim.length();
202 
203                 if (pathHyperlinkPaths.contains(path)) {
204                     addHyperlink(new PathHyperlinkData(startIndex, endIndex, trim));
205                 } else {
206                     String internalTypeName = trim.replace('.', '/');
207                     addHyperlink(new TypeHyperlinkData(startIndex, endIndex, internalTypeName));
208                 }
209             }
210         }
211     }
212 }
213