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

com.pekinsoft.validation.conversion.Converter Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */
package com.pekinsoft.validation.conversion;

import com.pekinsoft.lookup.Lookup;
import com.pekinsoft.validation.Validator;
import com.pekinsoft.validation.ValidatorUtils;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * Converts validators. Can convert a {@link Validator} working on one type (such as {@code String})
 * to a `Validator` of a different type, such as `javax.swing.text.Document`.
 * In this way, it is possible to write only validators
 * for {@code String}s, but use them against `javax.swing.text.Document`s (for validating
 * {@code JTextField} and {@code JTextArea} components), etc.
 *
 * @author Tim Boudreau
 */
public abstract class Converter {
    private static Set > registry = new HashSet>();
    private final Class from;
    private final Class to;
    protected Converter (Class from, Class to) {
        this.from = from;
        this.to = to;
    }

    public final Class from() {
        return from;
    }

    public final Class to() {
        return to;
    }

    /**
     * Create a {@link Validator} for type {@code To} from a validator for type
     * {@code From}. For example, a converter that is a factory for Validators
     * of {@code javax.swing.text.Document}s from a validator
     * that only handles Strings may be created. (Convert would simply return a
     * Validator<Document> that wraps the Validator<String>. At validation time
     * it will first call Document.getText(), and then pass the result to
     * the wrapped Validator<String>).
     * @param from The original validator.
     * @return A validator of the type requested
     */
    public abstract Validator convert (Validator from);

    /**
     * Will merge the chain of passed validators to one, and then convert it to 
     * the requested type. See {@link #convert(com.pekinsoft.validation.Validator) }
     * 
     * @param froms A chain of validator to convert.
     * @return A validator of the type requested
     */
    public final Validator convert (Validator... froms) {
        return (convert(ValidatorUtils.merge(froms)));
    }

    /**
     * Register a converter
     * 
     * @param converter
     */
    public static void register (Converter converter) {
        registry.add (converter);
    }

    static {
        Converter.register (new StringToDocumentConverter());
        Converter.register (new StringToComboBoxModelConverter());
        Converter.register (new SelectedIndicesToListSelectionModelConverter());
        Converter.register (new SelectedIndicesToButtonModelArrayConverter());
    }

    /**
     * Find a converter to create validators for one type from validators for
     * another type.
     * @param  The type of object we get from a component, such as a
     * `javax.swing.text.Document`
     * @param  The type of object we want to process, such as a
     * `java.lang.String`
     * @param from A class, such as `Document.class`
     * @param to A class such as `String.class`
     * @return An object which can take validators for type `From`
     * and produce validators for type `To`
     */
    public static Converter find (Class from, Class to) {
        Collection converters 
                = Lookup.getDefault().lookupAll(Converter.class);
        for (Converter c : converters) {
            if (c.match(from,to)) {
                return c.as(from, to);
            }
        }
        for (Converter c : registry) {
            if (c.match(from, to)) {
                return c.as(from, to);
            }
        }
        throw new IllegalArgumentException ("No registered converter from " +
                from.getName() + " to " + to.getName());
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Converter other = (Converter) obj;
        if (this.from != other.from && (this.from == null || !this.from.equals(other.from))) {
            return false;
        }
        if (this.to != other.to && (this.to == null || !this.to.equals(other.to))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 23 * hash + (this.from != null ? this.from.hashCode() : 0);
        hash = 11 * hash + (this.to != null ? this.to.hashCode() : 0);
        return hash;
    }

    private boolean match (Class from, Class to) {
//        return from().isAssignableFrom(from) && to().isAssignableFrom(to);
        return from().equals(from) && to().equals(to);
    }
    
     Converter as (Class t, Class r) {
        return new Wrap(t, r, this);
    }


    static final class Wrap extends Converter {
        final Converter other;
        private final Exception ex;
        Wrap (Class a, Class b, Converter other) {
            super (a,b);
            this.other = other;
            ex = new Exception();
        }

        @Override
        public Validator convert(Validator from) {
            Validator tv = ValidatorUtils.cast (other.from, from);
            Validator cvt = other.convert(tv);
            return ValidatorUtils.cast(to(), cvt);
        }
    }
//    private static final class DepthComparator implements Comparator> {
//        int classDepth(Class type) {
//            int depth = 0;
//            Set> set = new HashSet>();
//            for (;type != null; type = type.getSuperclass()) {
//                set.addAll(Arrays.asList(type.getInterfaces()));
//                depth++;
//            }
//            return depth + set.size();
//        }
//
//        public int compare(Converter o1, Converter o2) {
//            return classDepth(o1.from()) - classDepth(o2.from());
//        }
//    }
}