net.aepik.alasca.core.ldap.Schema.java Source code

Java tutorial

Introduction

Here is the source code for net.aepik.alasca.core.ldap.Schema.java

Source

/*
 * Copyright (C) 2006-2010 Thomas Chemineau
 * 
 * This program 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 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package net.aepik.alasca.core.ldap;

import net.aepik.alasca.core.History;
import net.aepik.alasca.core.ldap.value.Oid;
import org.apache.commons.lang3.ArrayUtils;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Observable;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import java.util.jar.*;

/**
 * Cet objet est un schma LDAP au sens large. Il doit contenir des dfinitions
 * de type objectClass ou AttributeType, par l'intermdiaire de l'objet Java
 * SchemaObject.
 */
public class Schema extends Observable {

    /**
     * L'ensemble des objets du schema
     */
    private Hashtable<String, SchemaObject> objets;

    /**
     * Schema properties
     */
    private Properties proprietes;

    /**
     * La syntaxe du schema
     */
    private SchemaSyntax syntax;

    /**
     * Indique si la syntaxe a change
     */
    private boolean isSyntaxChanged;

    /**
     * Schema name.
     * @var String
     */
    private String name;

    /**
     * L'historique d'ordre des objets
     */
    private History objectsOrder;

    /**
     * A random object identifier prefix
     */
    private String objectIdentifierPrefix;

    /**
     * A random object identifier suffix
     */
    private String objectIdentifierSuffix;

    /**
     * Construit un schema vide.
     * @param name Schema name
     * @param s Schema syntax
     */
    public Schema(String name, SchemaSyntax s) {
        this.name = name;
        objets = new Hashtable<String, SchemaObject>();
        proprietes = new Properties();
        syntax = s;
        isSyntaxChanged = false;
        objectsOrder = new History();
        objectIdentifierPrefix = null;
        objectIdentifierSuffix = null;
    }

    /**
     * Construit un schema en le remplissant
     * d'objets SchemaObject.
     * @param name Schema name
     * @param s Schema syntax
     * @param objs Des objets du schema.
     */
    public Schema(String name, SchemaSyntax s, Vector<SchemaObject> objs) {
        this.name = name;
        objets = new Hashtable<String, SchemaObject>();
        proprietes = new Properties();
        syntax = s;
        isSyntaxChanged = false;
        addObjects(objs);
        objectIdentifierPrefix = null;
        objectIdentifierSuffix = null;
    }

    /**
     * Ajoute un objet au schema.
     * @param o Un objet du schema.
     * @return True si l'objet n'existe pas dj, false sinon.
     */
    public boolean addObject(SchemaObject o) {
        try {
            if (o == null || o.getId() == null) {
                return false;
            }
            if (!contains(o.getId())) {
                objets.put(o.getId(), o);
                objectsOrder.insertElementInLastPosition(o);
                notifyUpdates();
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Ajoute un objet au schema mme s'il existe.
     * @param o Un objet du schema.
     * @return True si l'ajout s'est bien pass, false sinon.
     */
    public boolean addOrReplaceObject(SchemaObject o) {
        try {
            if (o == null || o.getId() == null) {
                return false;
            }
            objets.put(o.getId(), o);
            notifyUpdates();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Ajoute un ensemble d'objets au schema.
     * @param v Un ensemble d'objets du schema.
     * @return True si l'opration a russi, false sinon.
     *      Si l'opration n'a pas russi, aucun objet n'aura t ajout.
     */
    public boolean addObjects(SchemaObject[] v) {
        boolean ok = true;
        for (int i = 0; i < v.length && ok; i++) {
            ok = addObject(v[i]);
        }
        if (ok) {
            notifyUpdates();
            return true;
        }
        //
        // Si l'opration n'a pas russi, c'est  dire qu'un objet, figurant
        // dans l'ensemble des objets que l'on tente d'insrer, possde un id
        // qui existe dj dans le schema courant, alors on effectue
        // l'opration inverse: on supprime tout objet insr durant
        // l'opration prcdente.
        //
        for (SchemaObject o : v) {
            delObject(o.getId());
        }
        return false;
    }

    /**
     * Ajoute un ensemble d'objets au schema.
     * @param v Un ensemble d'objets du schema.
     * @return True si l'opration a russi, false sinon.
     *      Si l'opration n'a pas russi, aucun objet n'aura t ajout.
     */
    public boolean addObjects(Vector<SchemaObject> v) {
        SchemaObject[] o = new SchemaObject[v.size()];
        Iterator<SchemaObject> it = v.iterator();
        int position = 0;
        while (it.hasNext()) {
            o[position] = it.next();
            position++;
        }
        return addObjects(o);
    }

    /**
     * Indique si l'objet identifi par id existe dans le schema.
     * @param id Une chaine de caractres reprsentant l'id d'un objet du schma.
     * @return True si l'objet d'identifiant id existe dans le schema, false sinon.
     */
    public boolean contains(String id) {
        try {
            if (id == null || objets == null) {
                return false;
            }
            if (objets.containsKey(id)) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Retourne le nombre d'objets que contient le schma.
     * @return int Le nombre d'objets du schma.
     */
    public int countObjects() {
        return objets.size();
    }

    /**
     * Crer un schma et charge les objets lu  partir d'un fichier dans ce
     * nouveau schma.
     * @param SchemaSyntax syntax
     * @param String filename
     * @param boolean load
     * @return SchemaFile Un objet SchemaFile contenant les objets.
     */
    public static SchemaFile createAndLoad(SchemaSyntax syntax, String filename, boolean load) {
        SchemaFileReader sReader = syntax.createSchemaReader();
        SchemaFile sFile = new SchemaFile(filename, sReader, null);
        if (load) {
            sFile.read();
        }
        return sFile;
    }

    /**
     * Supprime un objet du schema.
     * @param id Une chaine de caractres reprsentant l'id d'un objet du schema.
     * @return True si l'objet d'identifiant id existe dans le schema, false sinon.
     */
    public boolean delObject(String id) {
        if (contains(id)) {
            SchemaObject o = objets.remove(id);
            objectsOrder.removeElement(o);
            notifyUpdates();
            return true;
        }
        return false;
    }

    /**
     * Generate a random object identifier.
     * @return String A random object identifier string.
     */
    public String generateRandomObjectIdentifier() {
        if (this.objectIdentifierPrefix == null) {
            objectIdentifierPrefix = new String("0.1.2.3.4.5.6");
        }
        if (this.objectIdentifierSuffix == null) {
            objectIdentifierSuffix = new String("0");
        }
        int suffix = (new Integer(objectIdentifierSuffix)).intValue();
        objectIdentifierSuffix = String.valueOf(++suffix);
        String roid = new String(objectIdentifierPrefix + "." + objectIdentifierSuffix);
        return roid;
    }

    /**
     * Retourne l'historique d'ajout du schma.
     * @return History Un historique en fonction des donnes actuelles du schma.
     */
    public History getHistory() {
        return objectsOrder;
    }

    /**
     * Get the name of this schema.
     * @return String
     */
    public String getName() {
        return this.name;
    }

    /**
     * Accde  un objet du schema.
     * @param id Une chaine de caractres reprsentant l'id d'un objet du schema.
     * @return SchemaObject Un objet du schema.
     */
    public SchemaObject getObject(String id) {
        if (contains(id)) {
            return objets.get(id);
        }
        return null;
    }

    /**
     * Retourne un objet du schma dont le nom est name.
     * @param name Le nom d'un objet, et non son id.
     * @return SchemaObject Un objet du schma.
     */
    public SchemaObject getObjectByName(String name) {
        SchemaObject result = null;
        Enumeration<SchemaObject> it = objets.elements();
        while (result == null && it.hasMoreElements()) {
            SchemaObject o = it.nextElement();
            String oName = o.getName();
            if (oName == null) {
                continue;
            }
            if (oName.toLowerCase().equals(name.toLowerCase())) {
                result = o;
                continue;
            }
            String oNameFirst = o.getNameFirstValue();
            if (oNameFirst.toLowerCase().equals(name.toLowerCase())) {
                result = o;
                continue;
            }
        }
        return result;
    }

    /**
     * Retourne l'ensemble des objets du schema.
     * @return SchemaObject[] L'ensemble des objets du schema.
     */
    public SchemaObject[] getObjects() {
        SchemaObject[] result = new SchemaObject[objets.size()];
        int position = 0;
        for (Enumeration<SchemaObject> e = objets.elements(); e.hasMoreElements();) {
            result[position] = e.nextElement();
            position++;
        }
        return result;
    }

    /**
     * Retourne l'ensemble des objets du schema d'un certain type.
     * @param type Le type des objets  selectionner.
     * @return SchemaObject[] L'ensemble des objets du schema.
     */
    public SchemaObject[] getObjects(String type) {
        Vector<SchemaObject> v = new Vector<SchemaObject>();
        for (Enumeration<SchemaObject> e = objets.elements(); e.hasMoreElements();) {
            SchemaObject o = e.nextElement();
            if (type.equals(o.getType())) {
                v.add(o);
            }
        }
        SchemaObject[] result = new SchemaObject[v.size()];
        int position = 0;
        for (Enumeration<SchemaObject> e = v.elements(); e.hasMoreElements();) {
            result[position] = e.nextElement();
            position++;
        }
        return result;
    }

    /**
     * Retourne l'ensemble des objets du schema dans l'ordre dans lequel
     * ils ont t ajout au schma.
     * @return SchemaObject[] L'ensemble des objets du schema.
     */
    public SchemaObject[] getObjectsInOrder() {
        Vector<SchemaObject> result = new Vector<SchemaObject>();
        for (SchemaObject o : this.getObjectsInOrder(this.getSyntax().getObjectIdentifierType())) {
            result.add(o);
        }
        for (SchemaObject o : this.getObjectsInOrder(this.getSyntax().getAttributeType())) {
            result.add(o);
        }
        for (SchemaObject o : this.getObjectsInOrder(this.getSyntax().getObjectClassType())) {
            result.add(o);
        }
        return result.toArray(new SchemaObject[10]);
    }

    /**
     * Retourne l'ensemble des objets du schema d'un certain type, dans l'ordre
     * dans lequel ils ont t ajout au schma.
     * @param type Le type des objets  selectionner.
     * @return SchemaObject[] L'ensemble des objets du schema.
     */
    public SchemaObject[] getObjectsInOrder(String type) {
        Vector<SchemaObject> v = new Vector<SchemaObject>();
        for (Enumeration<Object> e = objectsOrder.elements(); e.hasMoreElements();) {
            SchemaObject o = (SchemaObject) e.nextElement();
            if (type.equals(o.getType())) {
                v.add(o);
            }
        }
        SchemaObject[] result = new SchemaObject[v.size()];
        int position = 0;
        for (Enumeration<SchemaObject> e = v.elements(); e.hasMoreElements();) {
            result[position] = e.nextElement();
            position++;
        }
        if (type.equals(this.getSyntax().getObjectIdentifierType())) {
            Properties oids = getObjectsIdentifiers(result);
            String[] oidsk = getSortedObjectsIdentifiersKeys(oids);
            result = new SchemaObject[oidsk.length];
            for (int i = 0; i < oidsk.length; i++) {
                for (Enumeration<SchemaObject> e = v.elements(); e.hasMoreElements();) {
                    SchemaObject o = e.nextElement();
                    String[] okeys = o.getKeys();
                    if (okeys[0].compareTo(oidsk[i]) == 0) {
                        result[i] = o;
                    }
                }
            }
        }
        return result;
    }

    /**
     * Returns objects identifiers.
     * @return Properties All objects identifiers.
     */
    public Properties getObjectsIdentifiers() {
        return getObjectsIdentifiers(this.getObjects(this.getSyntax().getObjectIdentifierType()));
    }

    /**
     * Returns objects identifiers.
     * @param oids SchemaObject array
     * @return Properties All objects identifiers.
     */
    public static Properties getObjectsIdentifiers(SchemaObject[] oids) {
        Properties objectsIdentifiers = new Properties();
        for (SchemaObject object : oids) {
            String[] keys = object.getKeys();
            SchemaValue value = object.getValue(keys[0]);
            objectsIdentifiers.setProperty(keys[0], value.toString());
        }
        return objectsIdentifiers;
    }

    /**
     * Get sorted object identifiers keys, to loop on object identifiers
     * into a valid order.
     * @param oids Object identifiers.
     * @return String[] Sorted keys
     */
    public static String[] getSortedObjectsIdentifiersKeys(Properties oids) {
        Hashtable<String, String> ht = new Hashtable<String, String>();
        for (Enumeration keys = oids.propertyNames(); keys.hasMoreElements();) {
            String k = (String) keys.nextElement();
            Oid o = new Oid(oids.getProperty(k));
            String v = o.toString();
            String p = o.getPrefix();
            while (p != null) {
                v = v.replaceFirst(p + ":", oids.getProperty(p) + ".");
                p = (new Oid(oids.getProperty(p))).getPrefix();
            }
            ht.put(v, k);
        }
        String[] st = ht.keySet().toArray(new String[0]);
        Arrays.sort(st);
        String[] result = new String[st.length];
        int result_index = 0;
        for (String k : st) {
            result[result_index] = ht.get(k);
            result_index++;
        }
        return result;
    }

    /**
     * Get objects sorted.
     * @return SchemaObject[] All schema objects sorted.
     */
    public SchemaObject[] getObjectsSorted() {
        SchemaObject[] objects = new SchemaObject[objets.size()];
        int position = 0;
        for (Enumeration<SchemaObject> e = objets.elements(); e.hasMoreElements(); position++) {
            objects[position] = e.nextElement();
        }
        return objects;
    }

    /**
     * Retourne les proprits du schma.
     * @return Properties L'ensemble des proprits du schma.
     */
    public Properties getProperties() {
        return proprietes;
    }

    /**
     * Retourne la syntaxe utilise par le schema.
     * @return SchemaSyntax Une syntaxe spcifique.
     */
    public SchemaSyntax getSyntax() {
        return syntax;
    }

    /**
     * Return a syntax object by name.
     */
    public static SchemaSyntax getSyntax(String name) {
        try {
            String packageName = getSyntaxPackageName();
            for (String syntaxe : getSyntaxes()) {
                Class object = Class.forName(packageName + "." + syntaxe);
                Field field = object.getField("SHORTNAME");
                if (field != null && name.equals(field.get(null).toString())) {
                    @SuppressWarnings("unchecked")
                    SchemaSyntax o = ((Class<SchemaSyntax>) Class.forName(packageName + "." + syntaxe))
                            .newInstance();
                    return o;
                }
            }
            for (String syntaxe : getSyntaxes()) {
                if (name.equals(syntaxe)) {
                    @SuppressWarnings("unchecked")
                    SchemaSyntax o = ((Class<SchemaSyntax>) Class.forName(packageName + "." + syntaxe))
                            .newInstance();
                    return o;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Retourne le nom du paquetage contenant toutes les syntaxes.
     * @return String Un nom de paquetage.
     */
    public static String getSyntaxPackageName() {
        Schema s = new Schema("", null);
        return s.getClass().getPackage().getName() + ".syntax";
    }

    /**
     * Retourne l'ensemble des syntaxes connues, qui sont
     * contenues dans le package 'ldap.syntax'.
     * @return String[] L'ensemble des noms de classes de syntaxes.
     */
    public static String[] getSyntaxes() {
        String[] result = null;
        try {
            String packageName = getSyntaxPackageName();
            URL url = Schema.class.getResource("/" + packageName.replace('.', '/'));
            if (url == null) {
                return null;
            }
            if (url.getProtocol().equals("jar")) {
                Vector<String> vectTmp = new Vector<String>();
                int index = url.getPath().indexOf('!');
                String path = URLDecoder.decode(url.getPath().substring(index + 1), "UTF-8");
                JarFile jarFile = new JarFile(URLDecoder.decode(url.getPath().substring(5, index), "UTF-8"));
                if (path.charAt(0) == '/') {
                    path = path.substring(1);
                }
                Enumeration<JarEntry> jarFiles = jarFile.entries();
                while (jarFiles.hasMoreElements()) {
                    JarEntry tmp = jarFiles.nextElement();
                    //
                    // Pour chaque fichier dans le jar, on regarde si c'est un
                    // fichier de classe Java.
                    //
                    if (!tmp.isDirectory() && tmp.getName().substring(tmp.getName().length() - 6).equals(".class")
                            && tmp.getName().startsWith(path)) {
                        int i = tmp.getName().lastIndexOf('/');
                        String classname = tmp.getName().substring(i + 1, tmp.getName().length() - 6);
                        vectTmp.add(classname);
                    }
                }
                jarFile.close();
                result = new String[vectTmp.size()];
                for (int i = 0; i < vectTmp.size(); i++) {
                    result[i] = vectTmp.elementAt(i);
                }
            } else if (url.getProtocol().equals("file")) {
                //
                // On cr le fichier associ pour parcourir son contenu.
                // En l'occurence, c'est un dossier.
                //
                File[] files = (new File(url.toURI())).listFiles();
                //
                // On liste tous les fichiers qui sont dedans.
                // On les stocke dans un vecteur ...
                //
                Vector<File> vectTmp = new Vector<File>();
                for (File f : files) {
                    if (!f.isDirectory()) {
                        vectTmp.add(f);
                    }
                }
                //
                // ... pour ensuite les mettres dans le tableau de resultat.
                //
                result = new String[vectTmp.size()];
                for (int i = 0; i < vectTmp.size(); i++) {
                    String name = vectTmp.elementAt(i).getName();
                    int a = name.indexOf('.');
                    name = name.substring(0, a);
                    result[i] = name;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (result != null) {
            Arrays.sort(result);
        }
        return result;
    }

    /**
     * Return syntaxes short name.
     */
    public static String[] getSyntaxeNames() {
        return getSyntaxeNames(getSyntaxes());
    }

    /**
     * Return syntaxes short name.
     */
    public static String[] getSyntaxeNames(String[] names) {
        String[] syntaxes = names;
        try {
            String packageName = getSyntaxPackageName();
            for (int i = 0; i < syntaxes.length; i++) {
                Class object = Class.forName(packageName + "." + syntaxes[i]);
                Field field = object.getField("SHORTNAME");
                if (field != null) {
                    syntaxes[i] = field.get(null).toString();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return syntaxes;
    }

    /**
     * Teste si la syntaxe  changer depuis la dernire fois qu'on a appel
     * cette mthode.
     * @return boolean
     */
    public boolean isSyntaxChangedSinceLastTime() {
        if (isSyntaxChanged) {
            isSyntaxChanged = false;
            return true;
        }
        return false;
    }

    /**
     * Permet de notifier que les donnes ont changes.
     * Tous les objets observant le schema verront la notification.
     */
    public void notifyUpdates() {
        this.notifyUpdates(false);
    }

    /**
     * Permet de notifier que les donnes ont changes.
     * Tous les objets observant le schema verront la notification.
     * @param boolean force Indicates wheter or not to force the update.
     */
    public void notifyUpdates(boolean force) {
        setChanged();
        notifyObservers(Boolean.valueOf(force));
    }

    /**
     * Set a name for this schema.
     * @param String A name.
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Modify objects identifiers of this schema.
     * @param newOIDs New objects identifiers.
     */
    public void setObjectsIdentifiers(Properties newOIDs) {
        // Now delete existing oid.
        SchemaObject[] oids = this.getObjectsInOrder(this.getSyntax().getObjectIdentifierType());
        for (SchemaObject object : oids) {
            this.delObject(object.getId());
        }
        // And reimport the new one.
        for (Enumeration keys = newOIDs.propertyNames(); keys.hasMoreElements();) {
            String id = (String) keys.nextElement();
            SchemaValue v = this.getSyntax().createSchemaValue(this.getSyntax().getObjectIdentifierType(), id,
                    newOIDs.getProperty(id));
            SchemaObject o = this.getSyntax().createSchemaObject(this.getSyntax().getObjectIdentifierType(),
                    v.toString());
            o.addValue(id, v);
            this.addObject(o);
        }
    }

    /**
     * Modifies les proprits du schma.
     * @param newProp Le nouvel objet Properties.
     */
    public void setProperties(Properties newProp) {
        this.proprietes = newProp;
    }

    /**
     * Modifie la syntaxe du schma.
     * @param newSyntax Une syntaxe spcifique.
     */
    public void setSyntax(SchemaSyntax newSyntax) {
        isSyntaxChanged = true;
        syntax = newSyntax;
    }

}