Java tutorial
/* documentr - Edit, maintain, and present software documentation on the web. Copyright (C) 2012-2013 Maik Schreiber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.blizzy.documentr.markdown.macro.impl; import java.io.IOException; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.context.MessageSource; import org.springframework.security.core.Authentication; import com.google.common.base.Stopwatch; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import de.blizzy.documentr.access.DocumentrPermissionEvaluator; import de.blizzy.documentr.access.Permission; import de.blizzy.documentr.markdown.HtmlSerializerContext; import de.blizzy.documentr.markdown.macro.IMacroContext; import de.blizzy.documentr.markdown.macro.IMacroRunnable; import de.blizzy.documentr.markdown.macro.Macro; import de.blizzy.documentr.page.IPageStore; import de.blizzy.documentr.page.Page; import de.blizzy.documentr.util.Util; @Macro(name = "neighbors", insertText = "{{neighbors/}}", cacheable = false, dataHandler = NeighborsMacroDataHandler.class) @Slf4j public class NeighborsMacro implements IMacroRunnable { private HtmlSerializerContext htmlSerializerContext; private IPageStore pageStore; private DocumentrPermissionEvaluator permissionEvaluator; private Locale locale; private MessageSource messageSource; private String projectName; private String branchName; private String path; private int maxChildren; private boolean reorderAllowed; private LoadingCache<String, Page> pageCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Page>() { @Override public Page load(String path) throws IOException { return pageStore.getPage(projectName, branchName, path, false); } }); @Override public String getHtml(IMacroContext macroContext) { htmlSerializerContext = macroContext.getHtmlSerializerContext(); path = htmlSerializerContext.getPagePath(); if (path != null) { Map<String, String> params = Util.parseParameters(macroContext.getParameters()); try { String childrenStr = StringUtils.defaultIfBlank(params.get("children"), "1"); //$NON-NLS-1$ //$NON-NLS-2$ if (childrenStr.equals("all")) { //$NON-NLS-1$ maxChildren = Integer.MAX_VALUE; } else { maxChildren = Integer.parseInt(childrenStr); maxChildren = Math.max(maxChildren, 1); } } catch (NumberFormatException e) { maxChildren = 1; } pageStore = macroContext.getPageStore(); permissionEvaluator = macroContext.getPermissionEvaluator(); locale = macroContext.getLocale(); messageSource = macroContext.getMessageSource(); projectName = htmlSerializerContext.getProjectName(); branchName = htmlSerializerContext.getBranchName(); Authentication authentication = htmlSerializerContext.getAuthentication(); reorderAllowed = (locale != null) && (messageSource != null) && permissionEvaluator .hasBranchPermission(authentication, projectName, branchName, Permission.EDIT_PAGE); if (log.isInfoEnabled()) { log.info("rendering neighbors for page: {}/{}/{}, user: {}", //$NON-NLS-1$ projectName, branchName, Util.toUrlPagePath(path), authentication.getName()); } Stopwatch stopwatch = new Stopwatch().start(); try { StringBuilder buf = new StringBuilder(); Page page = getPage(path); buf.append("<span class=\"well well-small neighbors pull-right\"><ul class=\"nav nav-list\">") //$NON-NLS-1$ .append(printParent(printLinkListItem(page, 1, maxChildren), path)); if ((locale != null) && (messageSource != null)) { String hoverInfoText = messageSource.getMessage("neighborsItemsHoverExpandHelp", null, locale); //$NON-NLS-1$ buf.append("<div class=\"hover-help\">").append(hoverInfoText).append("</div>"); //$NON-NLS-1$ //$NON-NLS-2$ } buf.append("</ul></span>"); //$NON-NLS-1$ return buf.toString(); } catch (IOException e) { throw new RuntimeException(e); } finally { log.trace("rendering neighbors took {} ms", stopwatch.stop().elapsed(TimeUnit.MILLISECONDS)); //$NON-NLS-1$ } } else { return null; } } private CharSequence printParent(CharSequence inner, String path) throws IOException { StringBuilder buf = new StringBuilder(); Page page = getPage(path); if (page.getParentPagePath() != null) { if (hasViewPermission(page.getParentPagePath())) { StringBuilder parentBuf = new StringBuilder(); Page parentPage = getPage(page.getParentPagePath()); String uri = htmlSerializerContext.getPageUri(page.getParentPagePath()); parentBuf.append("<li><a href=\"").append(uri).append("\">") //$NON-NLS-1$ //$NON-NLS-2$ .append(parentPage.getTitle()).append("</a>") //$NON-NLS-1$ .append("<ul class=\"nav nav-list\">"); //$NON-NLS-1$ if (path.equals(this.path)) { List<Page> siblingPages = pageStore.listChildPagesOrdered(projectName, branchName, page.getParentPagePath(), locale); for (Page siblingPage : siblingPages) { parentBuf.append( siblingPage.getPath().equals(path) ? inner : printLinkListItem(siblingPage, 1, 0)); } } else { parentBuf.append(inner); } parentBuf.append("</ul>") //$NON-NLS-1$ .append("</li>"); //$NON-NLS-1$ buf.append(printParent(parentBuf, page.getParentPagePath())); } } else { buf.append(inner); } return buf; } private Page getPage(String path) throws IOException { try { return pageCache.get(path); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof IOException) { throw (IOException) cause; } else { throw new RuntimeException(cause); } } } private CharSequence printLinkListItem(Page page, int childLevel, int maxChildren) throws IOException { StringBuilder buf = new StringBuilder(); String pagePath = page.getPath(); if (hasViewPermission(pagePath)) { buf.append("<li data-path=\"").append(pagePath).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ if (reorderAllowed) { if (page.getOrderIndex() >= 0) { buf.append(" data-manual-order=\"true\""); //$NON-NLS-1$ } } boolean active = pagePath.equals(path); if (active) { buf.append(" class=\"active\""); //$NON-NLS-1$ } String title = page.getTitle(); String uri = htmlSerializerContext.getPageUri(pagePath); buf.append("><a href=\"").append(uri).append("\">") //$NON-NLS-1$ //$NON-NLS-2$ .append(title); if (active && reorderAllowed) { String buttonTitle = messageSource.getMessage("button.arrangePages", null, locale); //$NON-NLS-1$ buf.append("<span class=\"buttons pull-right\"><i class=\"icon-move icon-white\" title=\"") //$NON-NLS-1$ .append(buttonTitle) .append("\" onclick=\"startNeighborsArrange(); return false;\"></i></span>"); //$NON-NLS-1$ } buf.append("</a>"); //$NON-NLS-1$ buf.append(printChildren(pagePath, childLevel, maxChildren)).append("</li>"); //$NON-NLS-1$ } return buf; } private CharSequence printChildren(String path, int childLevel, int maxChildren) throws IOException { if (childLevel <= maxChildren) { StringBuilder buf = new StringBuilder(); List<Page> childPages = pageStore.listChildPagesOrdered(projectName, branchName, path, locale); if (!childPages.isEmpty()) { buf.append("<ul class=\"nav nav-list\">"); //$NON-NLS-1$ for (Page childPage : childPages) { buf.append(printLinkListItem(childPage, childLevel + 1, maxChildren)); } buf.append("</ul>"); //$NON-NLS-1$ } return buf; } else { return StringUtils.EMPTY; } } private boolean hasViewPermission(String path) { Authentication authentication = htmlSerializerContext.getAuthentication(); return permissionEvaluator.hasPagePermission(authentication, projectName, branchName, path, Permission.VIEW); } @Override public String cleanupHtml(String html) { return null; } }