org.apereo.portal.layout.dlm.FragmentDefinition.java Source code

Java tutorial

Introduction

Here is the source code for org.apereo.portal.layout.dlm.FragmentDefinition.java

Source

/**
 * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information regarding copyright ownership. Apereo
 * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use
 * this file except in compliance with the License. You may obtain a copy of the License at the
 * following location:
 *
 * <p>http://www.apache.org/licenses/LICENSE-2.0
 *
 * <p>Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apereo.portal.layout.dlm;

import java.util.LinkedList;
import java.util.List;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Transient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apereo.portal.layout.dlm.providers.EvaluatorGroup;
import org.apereo.portal.security.IPerson;
import org.apereo.portal.xml.XmlUtilitiesImpl;
import org.dom4j.DocumentHelper;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/** @since uPortal 2.5 */
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class FragmentDefinition extends EvaluatorGroup {

    /**
     * Still says 'jasig' becasue existing fragment-definition.xml files include it, and because (as
     * of yet) we still export them with that namespace.
     */
    public static final String NAMESPACE_URI = "http://org.jasig.portal.layout.dlm.config";

    public static final Namespace NAMESPACE = DocumentHelper.createNamespace("dlm", NAMESPACE_URI);

    /** User account whose layout should be copied to create a layout for new fragments. */
    private static final String cDefaultLayoutOwnerId = "fragmentTemplate";

    private static final Log LOG = LogFactory.getLog(FragmentDefinition.class);

    @Column(name = "FRAGMENT_NAME")
    private final String name;

    @Column(name = "OWNER_ID")
    private String ownerID = null;

    @Column(name = "PRECEDENCE")
    private double precedence = 0.0; // precedence of fragment

    @Column(name = "DESCRIPTION")
    private String description;

    /* These variables are bound to a uP userId later in the life cycle, not managed by hibernate */
    @Transient
    private int index = 0; // index of definition within config file
    @Transient
    String defaultLayoutOwnerID = null;

    /** No-arg constructor required by JPA/Hibernate. */
    @SuppressWarnings("unused")
    private FragmentDefinition() {
        this.name = null;
    }

    /*
     * For unit testing...
     */
    protected FragmentDefinition(String name) {
        this.name = name;
    }

    /**
     * This constructor is passed a dlm:fragment element from which this FragmentDefinition instance
     * gathers its configuration information.
     *
     * @param e An Element representing a single <dlm:fragment>
     * @throws Exception
     */
    public FragmentDefinition(Element e) {
        NamedNodeMap atts = e.getAttributes();
        this.name = loadAttribute("name", atts, true, e);

        loadFromEelement(e);
    }

    public void loadFromEelement(Element e) {
        final boolean REQUIRED = true;
        final boolean NOT_REQUIRED = false;

        NamedNodeMap atts = e.getAttributes();

        this.ownerID = loadAttribute("ownerID", atts, REQUIRED, e);
        this.defaultLayoutOwnerID = loadAttribute("defaultLayoutOwnerID", atts, NOT_REQUIRED, e);
        this.description = loadAttribute("description", atts, NOT_REQUIRED, e);

        String precedence = loadAttribute("precedence", atts, REQUIRED, e);
        try {
            this.precedence = Double.valueOf(precedence).doubleValue();
        } catch (NumberFormatException nfe) {
            throw new RuntimeException("Invalid format for precedence attribute " + "of <fragment> in\n'"
                    + XmlUtilitiesImpl.toString(e), nfe);
        }

        // Audience Evaluators.
        // NB:  We're about to re-parse the complete set of evaluators,
        // so we need to remove any that are already present.
        if (this.evaluators != null) {
            this.evaluators.clear();
        }
        loadAudienceEvaluators(e.getElementsByTagName("dlm:audience"));
    }

    public String getName() {
        return name;
    }

    public String getOwnerId() {
        return this.ownerID;
    }

    public double getPrecedence() {
        return this.precedence;
    }

    public String getDescription() {
        return description;
    }

    public static String getDefaultLayoutOwnerId() {
        return cDefaultLayoutOwnerId;
    }

    public List<Evaluator> getEvaluators() {
        return this.evaluators;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public boolean isNoAudienceIncluded() {
        return evaluators == null || evaluators.size() == 0;
    }

    private void loadAudienceEvaluators(NodeList nodes) {
        final String evaluatorFactoryAtt = "evaluatorFactory";

        for (int i = 0; i < nodes.getLength(); i++) {
            Node audience = nodes.item(i);
            NamedNodeMap atts = audience.getAttributes();
            Node att = atts.getNamedItem(evaluatorFactoryAtt);
            if (att == null || att.getNodeValue().equals(""))
                throw new RuntimeException(
                        "Required attibute '" + evaluatorFactoryAtt + "' " + "is missing or empty on 'audience' "
                                + " element in\n'" + XmlUtilitiesImpl.toString(audience) + "'");
            String className = att.getNodeValue();

            /*
             * For version 5.0, all uPortal sources were repackaged from 'org.jasig.portal'
             * to 'org.apereo.portal'.  *.fragment-definition.xml files exported from earlier
             * versions of uPortal will contain the old evaluatorFactory name.  We can detect
             * that and intervene here.
             */
            className = className.replace("org.jasig.portal", "org.apereo.portal");

            EvaluatorFactory factory = loadEvaluatorFactory(className, audience);
            addEvaluator(factory, audience);
        }
    }

    private void addEvaluator(EvaluatorFactory factory, Node audience) {
        Evaluator evaluator = factory.getEvaluator(audience);

        if (evaluator == null)
            throw new RuntimeException("Evaluator factory '" + factory.getClass().getName() + "' failed to "
                    + "return an evaluator for 'audience' element" + " in\n'" + XmlUtilitiesImpl.toString(audience)
                    + "'");
        if (evaluators == null) {
            evaluators = new LinkedList<Evaluator>();
        }
        evaluators.add(evaluator);
    }

    private EvaluatorFactory loadEvaluatorFactory(String factoryClassName, Node audience) {
        Class<?> theClass = null;
        try {
            theClass = Class.forName(factoryClassName);
        } catch (ClassNotFoundException cnfe) {
            throw new RuntimeException(
                    "java.lang.ClassNotFoundException occurred" + " while loading evaluator factory class '"
                            + factoryClassName + "' (or one of its " + "dependent classes) for 'audience' element "
                            + "in\n'" + XmlUtilitiesImpl.toString(audience) + "'");
        } catch (ExceptionInInitializerError eiie) {
            throw new RuntimeException("java.lang.ExceptionInInitializerError " + "occurred while "
                    + "loading evaluator factory Class '" + factoryClassName + "' (or one of its "
                    + "dependent classes) for 'audience' element " + "in\n'" + XmlUtilitiesImpl.toString(audience)
                    + "'. \nThis indicates that an exception " + "occurred during evaluation of a static"
                    + " initializer or the initializer for a " + "static variable.", eiie);
        } catch (LinkageError le) {
            throw new RuntimeException("java.lang.LinkageError occurred while "
                    + "loading evaluator factory Class '" + factoryClassName + "' for " + "'audience' element in\n'"
                    + XmlUtilitiesImpl.toString(audience) + "'. \nThis typically means that a "
                    + "dependent class has changed " + "incompatibly after compiling the " + "factory class.", le);
        }

        Object theInstance = null;

        try {
            theInstance = theClass.newInstance();
        } catch (IllegalAccessException iae) {
            throw new RuntimeException("java.lang.IllegalAccessException occurred "
                    + "while loading evaluator factory Class '" + factoryClassName + "' (or one of its "
                    + "dependent classes) for 'audience' element " + "in\n'" + XmlUtilitiesImpl.toString(audience)
                    + "' \nVerify that this is a public class " + "and that it contains a public, zero "
                    + "argument constructor.", iae);
        } catch (InstantiationException ie) {
            throw new RuntimeException("java.lang.InstantiationException occurred "
                    + "while loading evaluator factory Class '" + factoryClassName + "' (or one of its "
                    + "dependent classes) for 'audience' element " + "in\n'" + XmlUtilitiesImpl.toString(audience)
                    + "' \nVerify that the specified class is a " + "class and not an interface or abstract "
                    + "class.", ie);
        }
        try {
            return (EvaluatorFactory) theInstance;
        } catch (ClassCastException cce) {
            throw new RuntimeException("java.lang.ClassCastException occurred "
                    + "while loading evaluator factory Class '" + factoryClassName + "' (or one of its "
                    + "dependent classes) for 'audience' element " + "in\n'" + XmlUtilitiesImpl.toString(audience)
                    + "'. \nVerify that the class implements the " + "EvaluatorFactory interface.", cce);
        }
    }

    @Override
    public boolean isApplicable(IPerson p) {

        boolean isApplicable = false;
        if (LOG.isInfoEnabled())
            LOG.info(">>>> calling " + name + ".isApplicable( " + p.getAttribute("username") + " )");
        try {
            if (evaluators == null) {
                LOG.debug("isApplicable()=false due to evaluators collection being null");
            } else {
                for (Evaluator v : evaluators) {
                    if (v.isApplicable(p)) {
                        isApplicable = true;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to evaluate whether fragment '" + this.getName()
                    + "' is applicable to user '" + p.getUserName() + "'", e);
        }

        if (LOG.isInfoEnabled()) {
            LOG.info("---- " + name + ".isApplicable( " + p.getAttribute("username") + " )=" + isApplicable);
        }

        return isApplicable;
    }

    private String loadAttribute(String name, NamedNodeMap atts, boolean required, Element e) {
        Node att = atts.getNamedItem(name);
        if (required && (att == null || att.getNodeValue().equals("")))
            throw new RuntimeException("Missing or empty attribute '" + name + "' required by <fragment> in\n'"
                    + XmlUtilitiesImpl.toString(e) + "'");
        if (att == null)
            return null;
        return att.getNodeValue();
    }

    @Override
    public void toElement(org.dom4j.Element parent) {

        // Assertions.
        if (parent == null) {
            String msg = "Argument 'parent' cannot be null.";
            throw new IllegalArgumentException(msg);
        }

        QName q = new QName("fragment", FragmentDefinition.NAMESPACE);
        org.dom4j.Element rslt = DocumentHelper.createElement(q);
        rslt.addAttribute("name", this.getName());
        rslt.addAttribute("ownerID", this.getOwnerId());
        rslt.addAttribute("precedence", Double.toString(this.getPrecedence()));
        rslt.addAttribute("description", this.getDescription());

        // Serialize our children...
        for (Evaluator v : this.evaluators) {
            v.toElement(rslt);
        }

        parent.add(rslt);
    }

    @Override
    public Class<? extends EvaluatorFactory> getFactoryClass() {
        String msg = "This method is not necessary for serializing " + "FragmentDefinition instances and should "
                + "not be invoked.";
        throw new UnsupportedOperationException(msg);
    }

    @Override
    public String getSummary() {
        // This method is for audience evaluators...
        throw new UnsupportedOperationException();
    }
}