All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.customware.confluence.reporting.ReportBuilder Maven / Gradle / Ivy

/*
 * Copyright (c) 2007, CustomWare Asia Pacific
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of "CustomWare Asia Pacific" nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package net.customware.confluence.reporting;

import com.atlassian.confluence.core.ContentEntityObject;
import com.atlassian.confluence.renderer.PageContext;
import com.atlassian.renderer.v2.RenderMode;
import com.atlassian.renderer.v2.macro.Macro;
import net.customware.confluence.reporting.macro.AbstractReportMacro;
import net.customware.confluence.reporting.query.Mutatable;
import net.customware.confluence.reporting.query.Query;
import net.customware.confluence.reporting.query.Queryable;
import org.apache.commons.lang.mutable.Mutable;

import java.util.Set;

/**
 * Provides utility functions for handling reports.
 */
public final class ReportBuilder {
    private static final ReportContext DEFAULT = new DefaultReportContext();

    private static ReportContextFinder finder = new ReportContextFinder();

    private ReportBuilder() {
    }

    private static ReportContext getReportContext() throws ReportException {
        Set ctxs = finder.getThings();
        switch ( ctxs.size() ) {
            case 0:
                return DEFAULT;
            case 1:
                return ctxs.iterator().next();
            default:
                throw new ReportException( "There must be at most one report context available, but there are "
                        + ctxs.size() );
        }
    }

    /**
     * This method is called by macros which support being top-level macros.
     * Typically these are reports (e.g. subclasses of
     * {@link AbstractReportMacro}). All report-generation code must take place
     * within the context of the supplied executor's
     * {@link Executor#execute()} method - all other attempts to modify the
     * report context will throw {@link ContextException}s.
     * 
     * @param pageContext
     *            The current page context.
     * @param executor
     *            The executor containing report code.
     * @return the return value of the {@link Executor#execute()} method.
     * @throws ReportException
     *             if there is a problem while executing.
     */
    public static  T executeRoot( PageContext pageContext, Executor executor )
            throws ReportException {
        return getReportContext().executeRoot( pageContext, executor );
    }

    /**
     * This method is called by macros which support being top-level macros and
     * then wish to execute a single context object at that level.
     * 
     * @param 
     *            The type to return.
     * @param pageContext
     *            The current page context.
     * @param context
     *            The context object to execute with
     *            {@link #executeContext(Object, Executor)}.
     * @param executor
     *            The executor.
     * @return The executed value.
     * @throws ReportException
     *             if there is a problem.
     */
    public static  T executeRoot( PageContext pageContext, final Object context,
            final Executor executor ) throws ReportException {
        return executeRoot( pageContext, new Executor() {
            public T execute() throws ReportException {
                return executeContext( context, executor );
            }
        } );
    }

    /**
     * This method is called by macros which support being top-level macros and
     * then wish to execute a single context object at that level.
     * 
     * @param 
     *            The type to return.
     * @param pageContext
     *            The current page context.
     * @param context
     *            The context object to execute with
     *            {@link #executeContext(Object, Executor)}.
     * @param executor
     *            The executor.
     * @return The executed value.
     * @throws ReportException
     *             if there is a problem.
     */
    public static  T executeRoot( PageContext pageContext, final Report report,
            final Executor executor ) throws ReportException {
        return executeRoot( pageContext, new Executor() {
            public T execute() throws ReportException {
                return executeReport( report, executor );
            }
        } );
    }

    /**
     * Checks if we are currently in the context of a report. Use this to check
     * the status before calling methods like {@link #getCurrentContext()},
     * {@link #getCurrentReport()} or {@link #getCurrentReportItem()}, which
     * will throw {@link ContextException}s if in a bad context.
     * 
     * @return true if in the context of a report.
     */
    public static boolean isReporting() {
        try {
            return getReportContext().isReporting();
        } catch ( ReportException e ) {
            return false;
        }
    }

    /**
     * This method is called when setting up a report. The current context is
     * what other macros access to set values like filters, sorters and other
     * configuration values. It must be called from within the context of an
     * executeRoot call.
     * 
     * @param context
     *            The context object to use.
     * @param executor
     *            The executor to process.
     * @return the return value from the {@link Executor#execute()} method.
     * @throws ContextException
     *             if there we are currently not in the context of a call to
     *             {@link #executeReport(PageContext, ReportBuilder.Executor)}
     * @throws ExecutionException
     *             if there were any errors during execution.
     */
    public static  T executeContext( Object context, Executor executor ) throws ReportException {
        return getReportContext().executeContext( context, executor );
    }

    /**
     * Executes the specified report. It must be called from within the context
     * of an executeRoot call.
     * 
     * @param report
     *            The report.
     * @param executor
     *            The executor.
     * @return the return value from the {@link Executor#execute()} method.
     * @throws ContextException
     *             if there we are currently not in the context of a call to
     *             {@link #executeReport(PageContext, ReportBuilder.Executor)}
     * @throws ExecutionException
     *             if there were any errors during execution.
     */
    public static  T executeReport( Report report, Executor executor )
            throws ReportException {
        return getReportContext().executeReport( report, executor );
    }

    /**
     * Returns the current report.
     * 
     * @return the current report.
     * @throws ReportException
     *             if not in the context of a report.
     */
    public static Report getCurrentReport() throws ReportException {
        return getReportContext().getCurrentReport();
    }

    /**
     * Returns the current context, as set via the
     * {@link #executeContext(Object, ReportBuilder.Executor)}
     * method.
     * 
     * @return the current context.
     * @throws ReportException
     *             if in not in the context of a report.
     */
    public static Object getCurrentContext() throws ReportException {
        return getReportContext().getCurrentContext();
    }

    /**
     * Returns the current context, first checking that it implements the target
     * class. If it does not, null is returned.
     * 
     * @param targetClass
     *            The target class of the context object.
     * @return The current context, if it is an instance of
     *         targetClass.
     * @throws ReportException
     *             If not in the context of a report.
     */
    public static  C getCurrentContext( Class targetClass ) throws ReportException {
        return getReportContext().getCurrentContext( targetClass );
    }

    /**
     * Returns the current context as a {@link Query} object.
     * 
     * @return the query or null if the current context is not a
     *         Query.
     * @throws ReportException
     *             if not in the context of a report.
     */
    public static Query getQuery() throws ReportException {
        return getCurrentContext( Query.class );
    }

    /**
     * Returns the current context as a {@link Sortable} object.
     * 
     * @return the sortable instance, or null if the current
     *         context is not a Sortable.
     * @throws ReportException
     *             if not currently in the context of a report.
     */
    public static Sortable getSortable() throws ReportException {
        return getCurrentContext( Sortable.class );
    }

    /**
     * Returns the current context as a {@link Filterable} object.
     * 
     * @return the filterable instance, or null if the current
     *         context is not a Filterable.
     * @throws ReportException
     *             if not currently in the context of a report.
     */
    public static Filterable getFilterable() throws ReportException {
        return getCurrentContext( Filterable.class );
    }

    /**
     * Returns the current context as a {@link Mutable} object.
     * 
     * @return the mutable instance, or null if the current context
     *         is not a Mutable.
     * @throws ReportException
     *             if not in the context of a report.
     */
    public static  Mutatable getMutatable( Class fromType, Class toType ) throws ReportException {
        Mutatable mutatable = getCurrentContext( Mutatable.class );
        if ( mutatable != null && fromType.isAssignableFrom( mutatable.getFromType() )
                && toType.isAssignableFrom( mutatable.getToType() ) )
            return ( Mutatable ) mutatable;
        return null;
    }

    /**
     * Returns the current item being reported on.
     * 
     * @return the current report item.
     * @throws ReportException
     *             if not currently in the context of a report.
     */
    public static Object getCurrentReportItem() throws ReportException {
        return getReportContext().getCurrentReportItem();
    }

    /**
     * Returns the root content object for the current servlet request. That is,
     * the actual page being viewed, as opposed to the one currently being
     * reported on.
     * 
     * @return The root content.
     * @throws ReportException
     *             if not currently in the context of a report.
     */
    public static PageContext getRootPageContext() throws ReportException {
        return getReportContext().getRootPageContext();
    }

    /**
     * Returns the root {@link ContentEntityObject} for the current location.
     * May be null.
     * 
     * @return the root content object.
     * @throws ReportException
     *             if not currently in the context of a report.
     */
    public static ContentEntityObject getRootContent() throws ReportException {
        PageContext ctx = getRootPageContext();
        if ( ctx != null )
            return ctx.getEntity();
        return null;
    }

    /**
     * Returns the current {@link PageContext}. If the current item is a
     * Confluence page or other content, that will be the page context.
     * Otherwise, the parent report will be asked for it's page context and so
     * on, up until the root context (which is usually the page being reported
     * on) if nothing else is available. It is possible this will return
     * null in certain contexts.
     * 
     * @return the current page context.
     * @throws ReportException
     *             if not currently in the context of a report.
     */
    public static PageContext getCurrentPageContext() throws ReportException {
        Report report = getCurrentReport();
        if ( report != null )
            return report.getPageContext();
        else
            return getRootPageContext();
    }

    /**
     * Returns the current context as a {@link Queryable} object.
     * 
     * @return the queryable instance, or null if the current
     *         context is not Queryable.
     * @throws ReportException
     *             if not currently in the context of a report.
     */
    public static  Queryable getQueryable( Class type ) throws ReportException {
        Queryable queryable = getCurrentContext( Queryable.class );
        if ( queryable != null && queryable.getQueryValueType() != null
                && queryable.getQueryValueType().isAssignableFrom( type ) )
            return ( Queryable ) queryable;
        return null;
    }

    /**
     * Returns the current context as a {@link Outputtable} object.
     * 
     * @return the outputtable instance, or null if the current
     *         context is not Outputtable.
     * @throws ReportException
     *             if not currently in the context of a report.
     */
    public static  Outputable getOutputable( Class outputType )
            throws ReportException {
        Outputable outputable = getCurrentContext( Outputable.class );
        if ( outputable != null && outputType.isAssignableFrom( outputable.getOutputType() ) )
            return ( Outputable ) outputable;
        return null;
    }

    /**
     * Returns the current context as a {@link ReportSetup} object.
     * 
     * @return the report setup instance, or null if the current
     *         context is not ReportSetup.
     * @throws ReportException
     *             if not currently in the context of a report.
     */
    public static  ReportSetup getReportSetup( Class outputType )
            throws ReportException {
        ReportSetup setup = getCurrentContext( ReportSetup.class );
        if ( setup != null && outputType.isAssignableFrom( setup.getOutputType() ) )
            return ( ReportSetup ) setup;
        return null;
    }

    public static String renderWiki( String wiki, RenderMode renderMode, Macro macro )
            throws ReportException {
        return getReportContext().renderWiki( wiki, renderMode, macro );
    }

    /**
     * Returns the current report item context, or the
     * defaultContext if none is available. It will process in the
     * following order, returning the first non-null value:
     * 
     * 
    *
  1. The current report item, if present.
  2. *
  3. The each ancestor's current report item, from parent to granparent, etc., if present
  4. *
  5. The root context
  6. *
  7. The default context provided
  8. *
* * @param defaultSource * The default context. * @return The result. */ public static Object getCurrentSource( Object defaultSource) { Object context = null; if ( isReporting() ) { try { Report report = ReportBuilder.getCurrentReport(); if ( report != null ) context = getTopReportItem( report ); if ( context == null ) context = ReportBuilder.getRootContent(); } catch ( ReportException e ) { // Shouldn't happen, but ignore anyway. } } if ( context == null ) context = defaultSource; return context; } public static Object getTopReportItem( Report report ) { Object item = report.getCurrentItem(); if ( item == null && report.getParent() != null ) { item = getTopReportItem( report.getParent() ); } return item; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy