View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.frontend.xeditor;
20  
21  import java.io.IOException;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.Map;
26  import java.util.Map.Entry;
27  import java.util.regex.Matcher;
28  import java.util.regex.Pattern;
29  
30  import javax.xml.transform.TransformerException;
31  
32  import org.apache.logging.log4j.LogManager;
33  import org.apache.logging.log4j.Logger;
34  import org.jdom2.Document;
35  import org.jdom2.Element;
36  import org.jdom2.JDOMException;
37  import org.jdom2.Namespace;
38  import org.jdom2.Verifier;
39  import org.mycore.common.MCRConstants;
40  import org.mycore.common.config.MCRConfiguration2;
41  import org.mycore.common.content.MCRSourceContent;
42  import org.mycore.common.xsl.MCRParameterCollector;
43  import org.mycore.frontend.xeditor.tracker.MCRBreakpoint;
44  import org.mycore.frontend.xeditor.tracker.MCRChangeTracker;
45  import org.mycore.frontend.xeditor.validation.MCRXEditorValidator;
46  import org.xml.sax.SAXException;
47  
48  /**
49   * @author Frank L\u00FCtzenkirchen
50   */
51  public class MCREditorSession {
52  
53      private static final Logger LOGGER = LogManager.getLogger(MCREditorSession.class);
54  
55      private static final Pattern PATTERN_URI = Pattern.compile("\\{\\$([^\\}]+)\\}");
56  
57      private String id;
58  
59      private String url;
60  
61      private Map<String, String[]> requestParameters = new HashMap<>();
62  
63      private Map<String, Object> variables;
64  
65      private String cancelURL;
66  
67      private Document editedXML;
68  
69      private MCRChangeTracker tracker = new MCRChangeTracker();
70  
71      private MCREditorSubmission submission = new MCREditorSubmission(this);
72  
73      private MCRXEditorValidator validator = new MCRXEditorValidator(this);
74  
75      private MCRXMLCleaner cleaner = new MCRXMLCleaner();
76  
77      private MCRXEditorPostProcessor postProcessor = getDefaultPostProcessorImplementation();
78  
79      private static MCRPostProcessorXSL getDefaultPostProcessorImplementation() {
80          return MCRConfiguration2.getOrThrow("MCR.XEditor.PostProcessor.Default", MCRConfiguration2::instantiateClass);
81      }
82  
83      public MCREditorSession(Map<String, String[]> requestParameters, MCRParameterCollector collector) {
84          // make a copy, the original may be re-used by servlet container
85          this.requestParameters.putAll(requestParameters);
86          this.variables = new HashMap<>(collector.getParameterMap());
87          removeIllegalVariables();
88      }
89  
90      public MCREditorSession() {
91          this(Collections.emptyMap(), new MCRParameterCollector());
92      }
93  
94      public Map<String, Object> getVariables() {
95          return variables;
96      }
97  
98      public void update(MCRParameterCollector collector) {
99          String currentLang = collector.getParameter("CurrentLang", null);
100         if (currentLang != null) {
101             variables.put("CurrentLang", currentLang);
102         }
103     }
104 
105     private void removeIllegalVariables() {
106         for (Iterator<Entry<String, Object>> entries = variables.entrySet().iterator(); entries.hasNext();) {
107             String name = entries.next().getKey();
108             String result = Verifier.checkXMLName(name);
109             if (result != null) {
110                 LOGGER.warn("Illegally named transformation parameter, removing {}", name);
111                 entries.remove();
112             }
113         }
114     }
115 
116     public void setID(String id) {
117         this.id = id;
118     }
119 
120     public String getID() {
121         return id;
122     }
123 
124     public String getCombinedSessionStepID() {
125         return id + "-" + tracker.getChangeCounter();
126     }
127 
128     public void setPageURL(String pageURL) {
129         if (url == null) {
130             this.url = pageURL.contains("?") ? pageURL.substring(0, pageURL.indexOf("?")) : pageURL;
131             LOGGER.debug("Editor page URL set to {}", this.url);
132         }
133     }
134 
135     public String getPageURL() {
136         return this.url;
137     }
138 
139     public String getRedirectURL(String anchor) {
140         return url + "?" + MCREditorSessionStore.XEDITOR_SESSION_PARAM + "=" + id
141             + (anchor != null ? "#" + anchor : "");
142     }
143 
144     public Map<String, String[]> getRequestParameters() {
145         return requestParameters;
146     }
147 
148     public String getCancelURL() {
149         return cancelURL;
150     }
151 
152     public void setCancelURL(String cancelURL) {
153         if (this.cancelURL != null) {
154             return;
155         }
156 
157         String cURL = replaceParameters(cancelURL);
158         if (!cURL.contains("{")) {
159             LOGGER.debug("{} set cancel URL to {}", id, cURL);
160             this.cancelURL = cURL;
161         }
162     }
163 
164     public String replaceParameters(String uri) {
165         Matcher m = PATTERN_URI.matcher(uri);
166         StringBuffer sb = new StringBuffer();
167         while (m.find()) {
168             String token = m.group(1);
169             Object value = variables.get(token);
170             m.appendReplacement(sb, value == null ? m.group().replace("$", "\\$") : value.toString());
171         }
172         m.appendTail(sb);
173         return sb.toString();
174     }
175 
176     public Document getEditedXML() {
177         return editedXML;
178     }
179 
180     public void setEditedXML(Document editedXML) throws JDOMException {
181         this.editedXML = editedXML;
182         addNamespacesFrom(editedXML.getRootElement());
183     }
184 
185     private void addNamespacesFrom(Element element) {
186         MCRConstants.registerNamespace(element.getNamespace());
187         for (Namespace ns : element.getAdditionalNamespaces()) {
188             MCRConstants.registerNamespace(ns);
189         }
190         for (Element child : element.getChildren()) {
191             addNamespacesFrom(child);
192         }
193     }
194 
195     public void setEditedXML(String uri) throws JDOMException, IOException, SAXException, TransformerException {
196         String uriRe = replaceParameters(uri);
197         if ((editedXML != null) || uriRe.contains("{")) {
198             return;
199         }
200 
201         LOGGER.info("Reading edited XML from {}", uriRe);
202         Document xml = MCRSourceContent.getInstance(uriRe).asXML();
203         setEditedXML(xml);
204         setBreakpoint("Reading XML from " + uriRe);
205     }
206 
207     public MCRBinding getRootBinding() throws JDOMException {
208         MCRBinding binding = new MCRBinding(editedXML, tracker);
209         binding.setVariables(variables);
210         return binding;
211     }
212 
213     public void setBreakpoint(String msg) {
214         if (editedXML != null) {
215             tracker.track(MCRBreakpoint.setBreakpoint(editedXML.getRootElement(), msg));
216         }
217     }
218 
219     public MCRChangeTracker getChangeTracker() {
220         return tracker;
221     }
222 
223     public MCREditorSubmission getSubmission() {
224         return submission;
225     }
226 
227     public MCRXEditorValidator getValidator() {
228         return validator;
229     }
230 
231     public MCRXMLCleaner getXMLCleaner() {
232         return cleaner;
233     }
234 
235     public MCRXEditorPostProcessor getPostProcessor() {
236         return postProcessor;
237     }
238 
239     protected void setPostProcessor(MCRXEditorPostProcessor postProcessor) {
240         this.postProcessor = postProcessor;
241     }
242 
243 }