BrightSide Workbench Full Report + Source Code
ElContext.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2018 Lluis TurrĂ³ Cutiller <http://www.turro.org/>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero 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  * This program 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 Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 package org.turro.elephant.web;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.nio.file.Path;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.TreeSet;
29 import java.util.function.Function;
30 import java.util.logging.Level;
31 import java.util.logging.Logger;
32 import javax.servlet.ServletException;
33 import org.turro.string.Strings;
34 import org.jdom.Document;
35 import org.jdom.Element;
36 import org.jdom.JDOMException;
37 import org.jdom.input.SAXBuilder;
38 import org.turro.collections.Item;
39 import org.turro.collections.Tree;
40 import org.turro.elephant.context.Application;
41 import org.turro.elephant.context.ElephantContext;
42 import org.turro.elephant.context.IConstructor;
43 import org.turro.elephant.context.IContext;
44 import org.turro.elephant.context.IElement;
45 import org.turro.elephant.impl.abstracts.AbstractElement;
46 import org.turro.elephant.impl.context.ContextFactory;
47 import org.turro.elephant.impl.repository.Repository;
48 import org.turro.elephant.impl.util.Files;
49 import org.turro.elephant.search.FoundList;
50 import org.turro.elephant.search.SearchFormatter;
51 import org.turro.elephant.user.menu.UserMenus;
52 import org.turro.elephant.web.context.WebContext;
53 import org.turro.elephant.web.context.WebResources;
54 import org.turro.plugin.contacts.IContact;
55 import org.turro.util.CompareUtil;
56 
61 public class ElContext implements Comparable<ElContext> {
62 
63  public static final String
64  CONTEXT_FOLDER = "/_internal",
65  CONTEXT_FILE = CONTEXT_FOLDER + "/context.xml",
66  CONTEXT_REPOSITORY = CONTEXT_FOLDER + "/repository";
67 
68  protected File folder;
69  protected String title, path, params;
70  protected int level;
71  protected Set<String> defaultLocales;
72  protected ElContext parent;
73  protected TreeSet<ElContext> children;
74 
76 
77  public ElContext() {
78  this("", null, new File(ElephantContext.getRealPath("/")), null);
79  }
80 
81  protected ElContext(String path, File folder, ElContext parent) {
82  this(path, null, folder, parent);
83  }
84 
85  protected ElContext(String path, String params, File folder, ElContext parent) {
86  this.path = path;
87  this.params = params;
88  this.folder = folder;
89  this.parent = parent;
90  init();
91  }
92 
93  public String getId() {
94  return folder.getName();
95  }
96 
97  public String getName() {
98  return Optional.ofNullable(webContext.getName()).orElse(getId());
99  }
100 
101  public String getFullPath() {
102  String tmp = ElephantContext.getRootWebPath() + path;
103  return (Strings.isBlank(tmp) ? "/" : tmp + (Strings.isBlank(params) ? "" : params));
104  }
105 
106  public String getWebPath() {
107  if(Strings.isBlank(webContext.getRedirect())) {
108  return getFullPath();
109  } else if(webContext.getRedirect().startsWith("/")) {
111  } else if(webContext.getRedirect().contains("://")) {
112  return webContext.getRedirect();
113  } else {
114  return getFullPath() + "/" + webContext.getRedirect();
115  }
116  }
117 
118  public String getPath() {
119  return path;
120  }
121 
122  public boolean inPath(ElContext context) {
123  return context.getFullPath().matches(getFullPath() + "(\\/.*)?");
124  }
125 
126  public int getLevel() {
127  return path == null ? 0 : path.split("\\/").length - 1;
128  }
129 
130  public File getFile() {
131  return folder;
132  }
133 
134  public String getVerbosePath() {
135  return getVerbosePath(null);
136  }
137 
138  public String getVerbosePath(ElContext root) {
139  String result = getName();
140  ElContext ctx = parent;
141  while(ctx != null && !ctx.equals(root)) {
142  result = ctx.getName() + " " + result;
143  ctx = ctx.parent;
144  }
145  return result;
146  }
147 
148  public String getTarget() {
149  return webContext.getTarget();
150  }
151 
152  public boolean isPublic() {
153  return Strings.isBlank(webContext.getRole());
154  }
155 
156  public boolean canShowTo(IContact contact) {
157  if(isPublic()) return true;
158  return contact.getPermissions().isInRole(webContext.getRole());
159  }
160 
161  public boolean canDisplay() {
162  return isSelectable() && (webContext.isShowAlways() || isInRole());
163  }
164 
165  public boolean hasRestrictions() {
166  return !(webContext.isShowInNavigators() && (webContext.isShowAlways() || Strings.isEmpty(webContext.getRole())));
167  }
168 
169  public boolean isSelectable() {
171  }
172 
173  public boolean isInRole() {
174  if(parent != null && !parent.isInRole()) return false;
175  if(Strings.isBlank(webContext.getRole())) return true;
177  }
178 
179  public boolean canPrint() {
180  return (webContext.isPrintContext() && isInRole());
181  }
182 
183  public ElContext getParent() {
184  return parent;
185  }
186 
187  public boolean isIndexable() {
188  return !webContext.isNoIndex() && Strings.isBlank(webContext.getRedirect()) &&
189  !getPath().startsWith("/user");
190  }
191 
192  public boolean isFollowable() {
193  return !webContext.isNoFollow();
194  }
195 
196  public TreeSet<ElContext> getChildren() {
197  generateDynamic();
198  return children;
199  }
200 
201  public TreeSet<ElContext> getStaticChildren() {
202  TreeSet<ElContext> statics = new TreeSet<>();
203  for(ElContext ctx : children) {
204  if(!ctx.getWebContext().isDynamic()) statics.add(ctx);
205  }
206  return statics;
207  }
208 
209  public TreeSet<ElContext> getVisibleChildren() {
210  TreeSet<ElContext> visible = new TreeSet<>();
211  for(ElContext ctx : children) {
212  if(ctx.canDisplay()) visible.add(ctx);
213  }
214  return visible;
215  }
216 
217  public TreeSet<ElContext> getSiblings() {
218  if(parent == null) {
219  TreeSet<ElContext> set = new TreeSet<>();
220  set.add(this);
221  return set;
222  } else {
223  return parent.getChildren();
224  }
225  }
226 
227  public TreeSet<ElContext> getVisibleSiblings() {
228  TreeSet<ElContext> visible = new TreeSet<>();
229  for(ElContext ctx : getSiblings()) {
230  if(ctx.canDisplay()) visible.add(ctx);
231  }
232  return visible;
233  }
234 
235  public TreeSet<ElContext> getAncestors() {
236  TreeSet<ElContext> ancestors = new TreeSet<>();
237  ElContext ctx = this;
238  while(ctx != null) {
239  ancestors.add(ctx);
240  ctx = ctx.parent;
241  }
242  return ancestors;
243  }
244 
246  if(getParent() != null) {
247  boolean found = false;
248  for (ElContext sibling : getVisibleSiblings().descendingSet()) {
249  if(found && sibling.canDisplay()) return getLastChildren(sibling);
250  if(sibling.equals(this)) found = true;
251  }
252  return getParent();
253  }
254  return null;
255  }
256 
257  private ElContext getLastChildren(ElContext context) {
258  TreeSet<ElContext> ctxs = context.getVisibleChildren();
259  if(!ctxs.isEmpty()) {
260  return getLastChildren(ctxs.last());
261  }
262  return context;
263  }
264 
265  public ElContext getNext(boolean doChildren) {
266  if(doChildren) {
267  TreeSet<ElContext> set = getVisibleChildren();
268  if(!set.isEmpty()) return set.first();
269  }
270  if(getParent() != null) {
271  boolean found = false;
272  for (ElContext sibling : getVisibleSiblings()) {
273  if(found && sibling.canDisplay()) return sibling;
274  if(sibling.equals(this)) found = true;
275  }
276  }
277  return parent.getNext(false);
278  }
279 
280  public IContext getContext() {
282  }
283 
284  public String getRepositoryPath() {
285  return WebContext.repository(Path.of(path)).toString();
286  }
287 
289  return new Repository(Application.getApplication().getConstructor(), WebContext.repository(Path.of(path)).toString());
290  }
291 
293  return folder != null ? new WebResources(folder.toPath()) : null;
294  }
295 
296  protected final void init() {
297  readConfiguration();
298  level = path == null ? 0 : path.split("\\/").length - 1;
299  ElContextMap.addContext(this);
300  if(children == null) {
301  children = new TreeSet<>();
302  if(folder.isDirectory()) {
303  File[] subfolders = folder.listFiles();
304  for(File subfolder: subfolders) {
305  if(subfolder.isDirectory() && !subfolder.isHidden()) {
306  if(!isInternal(subfolder)) {
307  if(Files.exists(path + "/" + subfolder.getName() + CONTEXT_FILE) ||
308  WebContext.existsConf(Path.of(path))) {
309  children.add(new ElContext(path + "/" + subfolder.getName(), subfolder, this));
310  }
311  }
312  }
313  }
314  }
315  }
316  }
317 
318  public Set<String> getDefaultLocales() {
319  if(defaultLocales == null) {
320  ElContext ctx = this;
321  while(ctx != null && ctx.webContext.getLangs().isEmpty()) {
322  ctx = ctx.parent;
323  }
325  }
326  return defaultLocales;
327  }
328 
330  return webContext;
331  }
332 
333  public static boolean isInternal(File file) {
334  if(file == null) return true;
335  String fileName = file.isFile() ? file.getName() : file.getAbsolutePath();
336  String internals = ElephantContext.getSiteInternalFiles();
337  if(internals != null) {
338  String tmp[] = internals.split(",");
339  for(String s : tmp) {
340  if(fileName.matches(Strings.convertToRegEx(s))) return true;
341  }
342  }
343  return (fileName.matches("google.*\\.html")) ||
344  (fileName.matches("site.*\\.xml")) ||
345  (fileName.matches("robots\\.txt")) ||
346  (fileName.contains("_internal")) ||
347  (fileName.contains("_zul")) ||
348  (fileName.contains("resources")) ||
349  (fileName.contains("WEB-INF")) ||
350  (fileName.contains("META-INF"));
351  }
352 
353  /* Construction */
354 
355  public void construct(IConstructor constructor) throws ServletException, IOException {
356  new ContextConstructor(constructor, this).start();
357  }
358 
359  public void setTitle(String title) {
360  this.title = title;
361  }
362 
363  public String getTitle() {
364  return Strings.isBlank(title) ? getName() : title;
365  }
366 
367  /* XML configuration, migration */
368 
369  private void readConfiguration() {
370  if(WebContext.existsConf(Path.of(path))) {
371  webContext = WebContext.loadFrom(Path.of(path));
372  } else {
373  webContext = new WebContext();
374  File confFile = new File(ElephantContext.getRealPath(this.path + CONTEXT_FILE));
375  Element conf = readConfFile(confFile);
376  if(conf != null) {
377  Element i18n = conf.getChild("i18n");
378  if(i18n != null) {
379  Element name = i18n.getChild("name");
380  if(name != null) {
381  for(Element language : (List<Element>) name.getChildren()) {
382  webContext.getNames().put(language.getName(), language.getValue());
383  }
384  }
385  }
386  webContext.setOrder(conf.getAttributeValue("order", "000"));
387  webContext.getLangs().addAll(Strings.csvToList(conf.getAttributeValue("lang")));
388  webContext.setShowInNavigators("true".equals(conf.getAttributeValue("showInNavigators", "true")));
389  webContext.setShowAlways("true".equals(conf.getAttributeValue("showAlways", "false")));
390  webContext.setPrintContext("true".equals(conf.getAttributeValue("printContext", "true")));
391  webContext.setRole(conf.getAttributeValue("contextRole"));
392  webContext.setRedirect(conf.getAttributeValue("redirect"));
393  webContext.setTarget(conf.getAttributeValue("target"));
394  webContext.setNoIndex("true".equals(conf.getAttributeValue("noindex", "false")));
395  webContext.setNoFollow("true".equals(conf.getAttributeValue("nofollow", "false")));
396  webContext.setPrintVersion("true".equals(conf.getAttributeValue("print-version", "true")));
397  webContext.setControlVersion("true".equals(conf.getAttributeValue("control-version", "true")));
398  webContext.setTraversalNavigation("true".equals(conf.getAttributeValue("traversalNavigation", "false")));
399  for(Element el : (List<Element>) conf.getChildren("element")) {
400  if(el != null) {
401  IContext ictx = getContext();
402  IElement iel = ContextFactory.getContextElement(ictx, el);
403  if(iel instanceof AbstractElement) {
404  ((AbstractElement) iel).setConfiguration(el, null);
405  el.getChildren("attrib").forEach(attrib -> {
407  ((Element) attrib).getAttributeValue("name"),
408  ((Element) attrib).getAttributeValue("value"));
409  });
410  webContext.getElement().setElementClass(iel.getClass().getCanonicalName());
411  iel = null;
412  }
413  }
414  }
415  Element layout = conf.getChild("layout");
416  if(layout != null) {
417  Element template = layout.getChild("template");
418  if(template != null) {
419  webContext.getLayout().setTemplate(template.getAttributeValue("name"));
420  }
421  Element localTemplate = layout.getChild("local-template");
422  if(localTemplate != null) {
423  webContext.getLayout().setLocal(localTemplate.getAttributeValue("name"));
424  }
425  }
426  WebContext.saveTo(Path.of(path), webContext);
427  }
428  }
429  }
430 
431  private Element readConfFile(File confFile) {
432  if(confFile.exists()) {
433  SAXBuilder builder = new SAXBuilder();
434  Document doc;
435  try {
436  doc = builder.build(confFile);
437  return doc.getRootElement();
438  } catch (IOException | JDOMException ex) {
439  Logger.getLogger(ElContext.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
440  }
441  }
442  return null;
443  }
444 
445  /* Element */
446 
447  public IElement getElement() {
450  return iel;
451  }
452 
453 // private IElement getElement(Element conf, String type) {
454 // if(conf != null) {
455 // for(Element el : (List<Element>) conf.getChildren("element")) {
456 // if(el != null) {
457 // IContext ictx = getContext();
458 // IElement iel = ContextFactory.getContextElement(ictx, el);
459 // if(iel != null) {
460 // iel.setConfiguration(el, null);
461 // el.getChildren("attrib").forEach(attrib -> {
462 // webContext.getElement().getAttributes().put(
463 // ((Element) attrib).getAttributeValue("name"),
464 // ((Element) attrib).getAttributeValue("value"));
465 // });
466 // webContext.getElement().setElementClass(iel.getClass().getCanonicalName());
467 // }
468 // return iel;
469 // }
470 // }
471 // }
472 // return null;
473 // }
474 
475  /* Submenus based in containing elements */
476 
477  private boolean dynamicDone = false;
478 
479  private void generateDynamic() {
480  if(!dynamicDone) {
481  // load categories as children
485  iel.setRootCategories(this);
486  }
487  dynamicDone = true;
488  }
489  }
490 
491  public void generateCategoriesChildren(Tree tree, Function<Item, String> onParam) {
492  for(Item item : (List<Item>) tree.getItems()) {
493  addCategoriesChildren(getPath(), item, onParam);
494  }
495  }
496 
497  private void addCategoriesChildren(String root, Item current, Function<Item, String> onParam) {
498  String tmpPath = root + current.getPath();
499  String realPath = ElephantContext.getRealPath(tmpPath);
500  if(!Strings.isBlank(realPath)) {
501  File subfolder = new File(realPath);
502  ElContext child = new ElContext(Strings.unpunctuateKeepPath(tmpPath), onParam.apply(current), subfolder, this);
503  child.webContext.setShowInNavigators(true);
504  child.webContext.setNoIndex(true);
505  child.webContext.setNoFollow(true);
506  child.webContext.setOrder(current.getValue() == null ? "000" : "001");
507  child.webContext.setDynamic(true);
508  children.add(child);
509  if(!current.isLeaf()) {
510  for(Item item : (List<Item>) current.getChildren()) {
511  child.addCategoriesChildren(root, item, onParam);
512  }
513  }
514  }
515  }
516 
517  /* Social */
518 
521  }
522 
523  /* Template */
524 
525  public String getTemplateRoot() {
526  return findRoot(this);
527  }
528 
529  private String findRoot(ElContext ctx) {
530  if(ctx == null) return ElephantContext.getTemplatesRoot();
531  if(!Strings.isBlank(ctx.webContext.getLayout().getRoot())) {
532  return ctx.webContext.getLayout().getRoot();
533  }
534  return findRoot(ctx.parent);
535  }
536 
537  public String getTemplate() {
538  if(!Strings.isBlank(webContext.getLayout().getLocal())) {
539  return webContext.getLayout().getLocal();
540  }
541  return findTemplate(this);
542  }
543 
544  private String findTemplate(ElContext ctx) {
545  if(ctx == null) return "default-web";
546  if(!Strings.isBlank(ctx.webContext.getLayout().getTemplate())) {
547  return ctx.webContext.getLayout().getTemplate();
548  }
549  return findTemplate(ctx.parent);
550  }
551 
552  /* Search */
553 
554  public FoundList search(String value, boolean ignoreCase) {
555  FoundList fl = new FoundList();
556  SearchFormatter sf = new SearchFormatter(value, ignoreCase);
557  sf.processLine(getName());
558  if(sf.wasFound()) {
559  fl.addItem(
560  getId() == null ? "" : getId(),
561  (getPath().length() == 0 ? "/" : getPath()),
562  "<img src='" + ElephantContext.getRootResourcePath() + "/_internal/system/images/context.gif'/>",
563  getName(),
564  sf.getResult(),
565  (double)sf.getFound(),
566  value
567  );
568  }
569  return fl;
570  }
571 
572  /* Utils */
573 
574  public static String extractPath(String path) {
575  if(path == null) {
576  path = "/";
577  } else {
578  int p = path.indexOf("?");
579  if(p > -1) {
580  path = path.substring(0, p);
581  }
582  }
583  return path;
584  }
585 
586  public void resetDefaultLocales() {
587  defaultLocales = null;
588  }
589 
590  /* Comparable */
591 
592  @Override
593  public int compareTo(ElContext o) {
594  int result = 0;
595  result = CompareUtil.compare(level, o.level);
596  if(result == 0) {
597  result = CompareUtil.compare(webContext.getOrder(), o.webContext.getOrder());
598  }
599  if(result == 0) {
600  result = CompareUtil.compare(getName(), o.getName());
601  }
602  if(result == 0) {
603  result = CompareUtil.compare(getId(), o.getId());
604  }
605  if(result == 0) {
606  result = CompareUtil.compare(path, o.path);
607  }
608  return result;
609  }
610 
611  /* Object */
612 
613  @Override
614  public int hashCode() {
615  int hash = 7;
616  hash = 89 * hash + Objects.hashCode(this.path);
617  return hash;
618  }
619 
620  @Override
621  public boolean equals(Object obj) {
622  if (this == obj) {
623  return true;
624  }
625  if (obj == null) {
626  return false;
627  }
628  if (getClass() != obj.getClass()) {
629  return false;
630  }
631  final ElContext other = (ElContext) obj;
632  if (!Objects.equals(this.path, other.path)) {
633  return false;
634  }
635  return true;
636  }
637 
638 }
static IContext getContext(IConstructor constructor)
static boolean exists(String path)
Definition: Files.java:80
void addItem(String id, String link, String image, String title, String value, double similarity, String query)
Definition: FoundList.java:66
static boolean isInRole(String path)
Definition: UserMenus.java:56
static ElContext addContext(ElContext context)
TreeSet< ElContext > children
Definition: ElContext.java:73
TreeSet< ElContext > getChildren()
Definition: ElContext.java:196
boolean equals(Object obj)
Definition: ElContext.java:621
TreeSet< ElContext > getSiblings()
Definition: ElContext.java:217
TreeSet< ElContext > getAncestors()
Definition: ElContext.java:235
TreeSet< ElContext > getStaticChildren()
Definition: ElContext.java:201
boolean inPath(ElContext context)
Definition: ElContext.java:122
FoundList search(String value, boolean ignoreCase)
Definition: ElContext.java:554
static boolean isInternal(File file)
Definition: ElContext.java:333
TreeSet< ElContext > getVisibleSiblings()
Definition: ElContext.java:227
ElContext getNext(boolean doChildren)
Definition: ElContext.java:265
ElContext(String path, String params, File folder, ElContext parent)
Definition: ElContext.java:85
boolean canShowTo(IContact contact)
Definition: ElContext.java:156
void generateCategoriesChildren(Tree tree, Function< Item, String > onParam)
Definition: ElContext.java:491
static String extractPath(String path)
Definition: ElContext.java:574
void construct(IConstructor constructor)
Definition: ElContext.java:355
ElContext(String path, File folder, ElContext parent)
Definition: ElContext.java:81
static final String CONTEXT_FOLDER
Definition: ElContext.java:64
String getVerbosePath(ElContext root)
Definition: ElContext.java:138
TreeSet< ElContext > getVisibleChildren()
Definition: ElContext.java:209
static SocialImage getImage(String url)
void setPrintContext(boolean printContext)
static boolean existsConf(Path path)
void setTraversalNavigation(boolean traversalNavigation)
Definition: WebContext.java:84
void setPrintVersion(boolean printVersion)
void setShowAlways(boolean showAlways)
Definition: WebContext.java:76
static WebContext loadFrom(Path path)
void setControlVersion(boolean controlVersion)
void setShowInNavigators(boolean showInNavigators)
Definition: WebContext.java:68
Map< String, String > getAttributes()
Definition: WebElement.java:56
void setElementClass(String elementClass)
Definition: WebElement.java:44
void setRootCategories(ElContext root)
void setConfiguration(IConstructor constructor, ElContext context)