PageRenderTime 38ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/org/randombits/filtering/confluence/criteria/content/ContentScopeCriterion.java

https://bitbucket.org/ianchiu/filtering-confluence
Java | 259 lines | 181 code | 41 blank | 37 comment | 60 complexity | 47b5876995916f044a9f63a6a4bde746 MD5 | raw file
  1. /*
  2. * Copyright (c) 2006, David Peterson
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * * Neither the name of "randombits.org" nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. * POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. package org.randombits.filtering.confluence.criteria.content;
  30. import java.util.Arrays;
  31. import java.util.Collection;
  32. import java.util.EnumSet;
  33. import java.util.Set;
  34. import org.randombits.filtering.core.criteria.CriteriaException;
  35. import org.randombits.filtering.core.criteria.Criterion;
  36. import org.randombits.filtering.core.criteria.CriterionInterpreter;
  37. import org.randombits.filtering.core.criteria.SourceCriterion;
  38. import org.randombits.support.confluence.LinkAssistant;
  39. import org.randombits.support.core.convert.ConversionAssistant;
  40. import org.randombits.support.core.convert.ConversionException;
  41. import com.atlassian.confluence.content.render.xhtml.DefaultConversionContext;
  42. import com.atlassian.confluence.core.ConfluenceEntityObject;
  43. import com.atlassian.confluence.core.ContentEntityObject;
  44. import com.atlassian.confluence.core.SpaceContentEntityObject;
  45. import com.atlassian.confluence.links.linktypes.AbstractContentEntityLink;
  46. import com.atlassian.confluence.pages.Attachment;
  47. import com.atlassian.confluence.pages.Comment;
  48. import com.atlassian.confluence.pages.Page;
  49. import com.atlassian.confluence.search.v2.SearchResult;
  50. import com.atlassian.confluence.spaces.Space;
  51. /**
  52. * Checks if the supplied object matches the scope criterion.
  53. *
  54. * @author David Peterson
  55. */
  56. public class ContentScopeCriterion implements SourceCriterion<ContentEntityObject> {
  57. public static class Interpreter implements CriterionInterpreter {
  58. /**
  59. * This marks the delimitation between the content and the scope.
  60. */
  61. public static final char SCOPE_DELIMITER = '>';
  62. private ContentEntityObject content;
  63. private final LinkAssistant linkAssistant;
  64. private final ConversionAssistant conversionAssistant;
  65. public Interpreter( LinkAssistant linkAssistant, ConversionAssistant conversionAssistant) {
  66. this( conversionAssistant, linkAssistant, null );
  67. }
  68. public Interpreter( ConversionAssistant conversionAssistant, LinkAssistant linkAssistant, ContentEntityObject content ) {
  69. this.content = content;
  70. this.linkAssistant = linkAssistant;
  71. this.conversionAssistant = conversionAssistant;
  72. }
  73. public Criterion createCriterion( String value ) throws CriteriaException {
  74. int scopeIndex = value.indexOf( SCOPE_DELIMITER );
  75. EnumSet<Scope> scope = EnumSet.noneOf( Scope.class );
  76. if ( scopeIndex >= 0 ) {
  77. String scopeString = value.substring( scopeIndex + 1 ).trim().toLowerCase();
  78. value = value.substring( 0, scopeIndex ).trim();
  79. if ( "ancestors".equals( scopeString ) ) {
  80. scope.add( Scope.ANCESTORS );
  81. } else if ( "children".equals( scopeString ) ) {
  82. scope.add( Scope.CHILDREN );
  83. } else if ( "descendents".equals( scopeString ) || "descendants".equals( scopeString ) ) {
  84. scope.add( Scope.DESCENDANTS );
  85. } else {
  86. throw new CriteriaException( "Unsupported scope: " + scopeString );
  87. }
  88. } else {
  89. scope.add( Scope.SELF );
  90. }
  91. ContentEntityObject context = null;
  92. if ( "@self".equals( value ) ) {
  93. context = this.content;
  94. } else if ( "@parent".equals( value ) ) {
  95. if ( content instanceof Page ) {
  96. context = ( (Page) content ).getParent();
  97. } else
  98. throw new CriteriaException( "@parent can only be used on pages." );
  99. } else if ( "@home".equals( value ) ) {
  100. if ( content instanceof SpaceContentEntityObject ) {
  101. Space space = ( (SpaceContentEntityObject) content ).getSpace();
  102. if ( space != null )
  103. context = space.getHomePage();
  104. }
  105. } else {
  106. ConfluenceEntityObject entity = linkAssistant.getEntityForWikiLink(
  107. new DefaultConversionContext( content.toPageContext() ), value );
  108. if ( entity instanceof ContentEntityObject )
  109. context = (ContentEntityObject) entity;
  110. }
  111. if ( context != null )
  112. return new ContentScopeCriterion(conversionAssistant, context, scope );
  113. else
  114. throw new CriteriaException( "Unable to locate the specified content: '" + value + "'" );
  115. }
  116. }
  117. public enum Scope {
  118. SELF, CHILDREN, DESCENDANTS, ANCESTORS
  119. }
  120. private ContentEntityObject rootContent;
  121. private final ConversionAssistant conversionAssistant;
  122. private EnumSet<Scope> scope;
  123. public ContentScopeCriterion( ConversionAssistant conversionAssistant, ContentEntityObject ceo ) {
  124. this(conversionAssistant, ceo, Scope.SELF );
  125. }
  126. public ContentScopeCriterion( ConversionAssistant conversionAssistant, ContentEntityObject ceo, Scope... scopes ) {
  127. this(conversionAssistant, ceo, EnumSet.copyOf( Arrays.asList( scopes ) ) );
  128. }
  129. public ContentScopeCriterion(ConversionAssistant conversionAssistant, ContentEntityObject ceo, EnumSet<Scope> scope ) {
  130. rootContent = ceo;
  131. this.scope = scope;
  132. this.conversionAssistant = conversionAssistant;
  133. }
  134. public boolean matches( Object object ) {
  135. ConfluenceEntityObject ceo = null;
  136. Object obj = object;
  137. if (object instanceof SearchResult
  138. && conversionAssistant.canConvert(object, ConfluenceEntityObject.class) ) {
  139. try {
  140. obj = conversionAssistant.convert(object, ConfluenceEntityObject.class);
  141. } catch (ConversionException e) {
  142. e.printStackTrace();
  143. }
  144. }
  145. if ( obj instanceof Comment ) {
  146. ceo = ( (Comment) obj ).getOwner();
  147. } else if ( obj instanceof Attachment ) {
  148. ceo = ( (Attachment) obj ).getContent();
  149. } else if ( obj instanceof AbstractContentEntityLink ) {
  150. ceo = ( (AbstractContentEntityLink) obj ).getDestinationContent();
  151. } else if ( obj instanceof ContentEntityObject ) {
  152. ceo = (ContentEntityObject) obj;
  153. }
  154. if ( ceo != null ) {
  155. if ( hasScope( Scope.SELF ) ) {
  156. if ( rootContent.equals( ceo ) )
  157. return true;
  158. }
  159. if ( !( scope.size() == 1 && scope.contains( Scope.SELF ) ) && rootContent instanceof Page && ceo instanceof Page ) {
  160. // there are other scopes set
  161. Page page = (Page) ceo;
  162. if ( hasScope( Scope.CHILDREN ) ) {
  163. if ( rootContent.equals( page.getParent() ) )
  164. return true;
  165. }
  166. if ( hasScope( Scope.DESCENDANTS ) ) {
  167. if ( isAncestor( page, (Page) rootContent ) )
  168. return true;
  169. }
  170. if ( hasScope( Scope.ANCESTORS ) ) {
  171. if ( isAncestor( (Page) rootContent, page ) )
  172. return true;
  173. }
  174. }
  175. }
  176. return false;
  177. }
  178. private boolean hasScope( Scope checkScope ) {
  179. return scope.contains( checkScope );
  180. }
  181. private boolean isAncestor( Page page, Page ancestor ) {
  182. page = page.getParent();
  183. while ( page != null && !page.equals( ancestor ) )
  184. page = page.getParent();
  185. return page != null;
  186. }
  187. @Override
  188. public String toString() {
  189. return "{content scope: "
  190. + rootContent
  191. + ( scope.size() == 0 ? "" : " >" + ( hasScope( Scope.CHILDREN ) ? " children" : "" )
  192. + ( hasScope( Scope.DESCENDANTS ) ? " descendents" : "" )
  193. + ( hasScope( Scope.ANCESTORS ) ? " ancestors" : "" ) ) + "}";
  194. }
  195. public Collection<ContentEntityObject> getMatchingValues() {
  196. Set<ContentEntityObject> values = new java.util.HashSet<ContentEntityObject>();
  197. if ( rootContent != null && !scope.isEmpty() ) {
  198. if ( hasScope( Scope.SELF ) ) {
  199. values.add( rootContent );
  200. }
  201. if ( rootContent instanceof Page ) {
  202. Page page = (Page) rootContent;
  203. if ( hasScope( Scope.DESCENDANTS ) ) {
  204. values.addAll( page.getDescendents() );
  205. } else if ( hasScope( Scope.CHILDREN ) ) {
  206. values.addAll( page.getChildren() );
  207. }
  208. if ( hasScope( Scope.ANCESTORS ) ) {
  209. values.addAll( page.getAncestors() );
  210. }
  211. }
  212. }
  213. return values;
  214. }
  215. public Weight getWeight() {
  216. return Weight.MEDIUM;
  217. }
  218. }