cat.albirar.framework.sets.impl.SetBuilderDefaultImpl.java Source code

Java tutorial

Introduction

Here is the source code for cat.albirar.framework.sets.impl.SetBuilderDefaultImpl.java

Source

/*
 * This file is part of "albirar-framework".
 * 
 * "albirar-framework" 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.
 * 
 * "albirar-framework" 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 calendar.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (C) 2015 Octavi Forns
 */

package cat.albirar.framework.sets.impl;

import java.beans.PropertyDescriptor;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;

import org.springframework.util.Assert;

import cat.albirar.framework.sets.ISet;
import cat.albirar.framework.sets.ISetBuilder;

/**
 * Default implementation of {@link ISetBuilder}.
 * @author Octavi Forns ofornes@albirar.cat
 * @since 2.1.0
 */
public class SetBuilderDefaultImpl<T> implements ISetBuilder<T> {
    /** Text to use if current path is empty for messages. */
    private static final String TEXT_FOR_EMPTY_CURRENT_PATH = "root";
    private Stack<ModelDescriptor> pathStack;
    private ModelDescriptor currentModelDescriptor;
    private List<String> properties;
    private Class<? extends T> rootModel;

    /**
     * Unique constructor.
     * @param rootModel The root model to build the {@link ISet}. <b>required</b>
     * @throws IllegalArgumentException If the {@code rootModel} is null
     */
    public SetBuilderDefaultImpl(Class<? extends T> rootModel) {
        Assert.notNull(rootModel, "The rootModel argument is required");
        this.rootModel = rootModel;
        pathStack = new Stack<ModelDescriptor>();
        properties = new Vector<String>();
        currentModelDescriptor = new ModelDescriptor(rootModel);
        // The root always on bottom of stack
        pathStack.push(currentModelDescriptor);
    }

    /**
     * {@inheritDocs}
     */
    @Override
    public ISetBuilder<T> addProperty(String propertyPath) {
        if (!checkPath(propertyPath)) {
            throw new IllegalArgumentException(
                    "The path denoted by '" + propertyPath + "' at '" + getCurrentPathOrRoot() + "' for model '"
                            + rootModel.getName() + "' doesn't exists. Cannot be added to set!");
        }

        properties.add(resolvePath(propertyPath));
        return this;
    }

    /**
     * {@inheritDocs}
     */
    @Override
    public ISetBuilder<T> pushPropertyPath(String propertyPath) {
        StringTokenizer stk;
        String spath;
        PropertyDescriptor pdesc;

        // Verify propertyPath
        Assert.hasText(propertyPath);
        stk = new StringTokenizer(propertyPath, ".");
        while (stk.hasMoreTokens()) {
            spath = stk.nextToken();
            if ((pdesc = currentModelDescriptor.getProperties().get(spath)) != null) {
                currentModelDescriptor = new ModelDescriptor(resolvePath(spath), propertyPath,
                        pdesc.getPropertyType());
            } else {
                throw new IllegalArgumentException(
                        "The path denoted by '" + propertyPath + "' at '" + getCurrentPathOrRoot() + "' for model '"
                                + rootModel.getName() + "' doesn't exists. Cannot be pushed!");
            }
        }
        pathStack.push(currentModelDescriptor);
        return this;
    }

    /**
     * {@inheritDocs}
     */
    @Override
    public ISetBuilder<T> popPropertyPath() {
        if (pathStack.size() > 1) {
            pathStack.pop();
            currentModelDescriptor = pathStack.peek();
        }
        return this;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String peekPropertyPathStack() {
        if (pathStack.size() > 1) {
            return pathStack.peek().getOriginalPath();
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void resetPropertyPathStack() {
        while (pathStack.size() > 1) {
            pathStack.pop();
        }
        currentModelDescriptor = pathStack.peek();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getCurrentPropertyPath() {
        return currentModelDescriptor.getRelativePath();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Class<? extends T> getModelRoot() {
        return rootModel;
    }

    /**
     * {@inheritDocs}
     */
    @Override
    public ISet<T> build() {
        ISet<T> s;

        s = new SetDefaultImpl<T>(rootModel);
        s.addAll(properties);
        return s;
    }

    /**
     * Gets the current path or {@value #TEXT_FOR_EMPTY_CURRENT_PATH} if current path is root.
     * @return The current path or the text of constant {@link #TEXT_FOR_EMPTY_CURRENT_PATH}
     */
    private String getCurrentPathOrRoot() {
        if (currentModelDescriptor.getRelativePath().isEmpty()) {
            return TEXT_FOR_EMPTY_CURRENT_PATH;
        }
        return currentModelDescriptor.getRelativePath();
    }

    /**
     * Check if path is correct for the root model.
     * @param propertyPath The property path
     * @return true if correct and false if not
     */
    private boolean checkPath(String propertyPath) {
        StringTokenizer stk;
        ModelDescriptor pathFollower;
        PropertyDescriptor pdesc;
        String ppath;

        stk = new StringTokenizer(propertyPath, ".");
        pathFollower = currentModelDescriptor;
        while (stk.hasMoreTokens()) {
            ppath = stk.nextToken();
            if ((pdesc = pathFollower.getProperties().get(ppath)) != null) {
                if (stk.hasMoreTokens()) {
                    pathFollower = new ModelDescriptor(pdesc.getPropertyType());
                }
            } else {
                // Error
                return false;
            }
        }
        return true;
    }

    /**
     * Resolve path with {@link #currentPath}.
     * @param relativePropertyPath The relative to {@link #currentPath} property path to resolve
     * @return the property path resolved
     */
    private String resolvePath(String relativePropertyPath) {
        return currentModelDescriptor.resolvePath(relativePropertyPath);
    }
}