/**
* Copyright 2009 Red Hat, Inc.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.safehaus.penrose.schema;
import org.safehaus.penrose.PenroseConfig;
import org.safehaus.penrose.schema.attributeSyntax.AttributeSyntax;
import org.safehaus.penrose.schema.attributeSyntax.AttributeSyntaxUtil;
import org.safehaus.penrose.directory.Entry;
import org.safehaus.penrose.directory.EntryConfig;
import org.safehaus.penrose.ldap.*;
import org.safehaus.penrose.naming.PenroseContext;
import org.safehaus.penrose.util.FileUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
/**
* @author Endi S. Dewata
*/
public class SchemaManager {
public Logger log = LoggerFactory.getLogger(getClass());
private PenroseConfig penroseConfig;
private PenroseContext penroseContext;
File home;
File schemaDir;
File extDir;
SchemaReader reader = new SchemaReader();
SchemaWriter writer = new SchemaWriter();
private Map<String,Schema> schemas = new TreeMap<String,Schema>();
private Map<String,Schema> builtInSchemas = new TreeMap<String,Schema>();
private Map<String,Schema> customSchemas = new TreeMap<String,Schema>();
private Schema schema = new Schema("DEFAULT");
public SchemaManager(File home) throws Exception {
this.home = home;
this.schemaDir = new File(home, "schema");
this.extDir = new File(schemaDir, "ext");
}
public File[] getSchemaFiles(File dir) {
return dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".schema");
}
});
}
public void loadSchemas() throws Exception {
//log.debug("Built-in schema files:");
File[] list = getSchemaFiles(schemaDir);
if (list != null) {
for (File schemaFile : list) {
//log.debug(" - "+schemaFile);
Schema schema = loadSchema(schemaFile);
addSchema(schema);
builtInSchemas.put(schema.getName(), schema);
}
}
//log.debug("Custom schema files:");
list = getSchemaFiles(extDir);
if (list != null) {
for (File schemaFile : list) {
//log.debug(" - "+schemaFile);
Schema schema = loadSchema(schemaFile);
addSchema(schema);
customSchemas.put(schema.getName(), schema);
}
}
}
public Schema loadSchema(File schemaFile) throws Exception {
return reader.read(schemaFile);
}
public void addSchema(Schema schema) throws Exception {
Logger log = LoggerFactory.getLogger(getClass());
boolean debug = log.isDebugEnabled();
String schemaName = schema.getName();
if (debug) log.debug("Adding schema \""+schemaName+"\".");
validate(schema);
schemas.put(schema.getName(), schema);
this.schema.add(schema);
}
public void validate(Schema schema) throws Exception {
String schemaName = schema.getName();
if (schemaName == null || "".equals(schemaName)) {
throw new Exception("Missing schema name.");
}
char startingChar = schemaName.charAt(0);
if (!Character.isLetter(startingChar)) {
throw new Exception("Invalid schema name: "+schemaName);
}
for (int i = 1; i<schemaName.length(); i++) {
char c = schemaName.charAt(i);
if (Character.isLetterOrDigit(c) || c == '_') continue;
throw new Exception("Invalid schema name: "+schemaName);
}
if (schemas.containsKey(schemaName)) {
throw new Exception("Schema "+schemaName+" already exists.");
}
}
public void createSchema(Schema schema) throws Exception {
addSchema(schema);
customSchemas.put(schema.getName(), schema);
File file = new File(extDir, schema.getName()+".schema");
writer.write(file, schema);
}
public void updateSchema(String schemaName, Schema schema) throws Exception {
Schema oldSchema = schemas.get(schemaName);
oldSchema.copy(schema);
if (!schemaName.equals(schema.getName())) {
File oldFile = new File(extDir, schemaName+".schema");
FileUtil.delete(oldFile);
schemas.remove(schemaName);
schemas.put(schema.getName(), schema);
if (builtInSchemas.containsKey(schemaName)) {
builtInSchemas.remove(schemaName);
builtInSchemas.put(schemaName, schema);
}
if (customSchemas.containsKey(schemaName)) {
customSchemas.remove(schemaName);
customSchemas.put(schemaName, schema);
}
}
File newFile = new File(extDir, schema.getName()+".schema");
writer.write(newFile, schema);
this.schema.clear();
for (Schema s : schemas.values()) {
this.schema.add(s);
}
}
public void storeSchema(String schemaName) throws Exception {
Schema schema = schemas.get(schemaName);
File file = new File(extDir, schemaName+".schema");
writer.write(file, schema);
}
public void removeSchema(String schemaName) {
File oldFile = new File(extDir, schemaName+".schema");
FileUtil.delete(oldFile);
schemas.remove(schemaName);
builtInSchemas.remove(schemaName);
customSchemas.remove(schemaName);
schema.clear();
for (Schema s : schemas.values()) {
schema.add(s);
}
}
public void clear() {
schemas.clear();
builtInSchemas.clear();
customSchemas.clear();
schema.clear();
}
public Collection<String> getSchemaNames() {
return schemas.keySet();
}
public Collection<String> getBuiltInSchemaNames() {
return builtInSchemas.keySet();
}
public Collection<String> getCustomSchemaNames() {
return customSchemas.keySet();
}
public Schema getSchema(String name) {
return schemas.get(name);
}
public Schema getSchema() {
return schema;
}
public Collection<ObjectClass> getObjectClasses() {
return schema.getObjectClasses();
}
public Collection<String> getObjectClassNames() {
return schema.getObjectClassNames();
}
public ObjectClass getObjectClass(String ocName) {
return schema.getObjectClass(ocName);
}
public Collection<ObjectClass> getAllObjectClasses(String ocName) {
return schema.getAllObjectClasses(ocName);
}
public Collection<String> getAllObjectClassNames(String ocName) {
return schema.getAllObjectClassNames(ocName);
}
public Collection<ObjectClass> getObjectClasses(Entry entry) {
return getObjectClasses(entry.getEntryConfig());
}
public Collection<ObjectClass> getObjectClasses(EntryConfig entryConfig) {
return schema.getObjectClasses(entryConfig);
}
public Collection<AttributeType> getAttributeTypes() {
return schema.getAttributeTypes();
}
public Collection<String> getAttributeTypeNames() {
return schema.getAttributeTypeNames();
}
public AttributeType getAttributeType(String attributeName) {
return schema.getAttributeType(attributeName);
}
public String normalizeAttributeName(String attributeName) {
boolean debug = log.isDebugEnabled();
AttributeType attributeType = getAttributeType(attributeName);
String normalizedAttributeName;
if (attributeType == null) {
if (debug) log.debug("Attribute type "+attributeName+" is undefined.");
normalizedAttributeName = attributeName;
} else {
normalizedAttributeName = attributeType.getName();
}
if (debug) log.debug("Normalize "+attributeName+" => "+normalizedAttributeName);
return normalizedAttributeName;
}
public PenroseConfig getPenroseConfig() {
return penroseConfig;
}
public void setPenroseConfig(PenroseConfig penroseConfig) {
this.penroseConfig = penroseConfig;
}
public PenroseContext getPenroseContext() {
return penroseContext;
}
public void setPenroseContext(PenroseContext penroseContext) {
this.penroseContext = penroseContext;
}
public RDN normalize(RDN rdn) {
if (rdn == null) return null;
RDNBuilder rb = new RDNBuilder();
for (String name : rdn.getNames()) {
Object value = rdn.get(name);
rb.set(normalizeAttributeName(name), value);
}
return rb.toRdn();
}
public DN normalize(DN dn) throws Exception {
if (dn == null) return null;
DNBuilder db = new DNBuilder();
RDNBuilder rb = new RDNBuilder();
for (RDN rdn : dn.getRdns()) {
rb.clear();
for (String name : rdn.getNames()) {
Object value = rdn.get(name);
rb.set(normalizeAttributeName(name), value);
}
db.append(rb.toRdn());
}
return db.toDn();
}
public Collection<String> normalize(Collection<String> attributeNames) {
if (attributeNames == null) return null;
Collection<String> list = new ArrayList<String>();
for (String name : attributeNames) {
list.add(normalizeAttributeName(name));
}
return list;
}
public Attributes normalize(Attributes attributes) throws Exception{
Collection<String> names = new ArrayList<String>(attributes.getNames());
for (String name : names) {
Collection<Object> values = attributes.getValues(name);
attributes.remove(name);
name = normalizeAttributeName(name);
attributes.setValues(name, values);
}
return attributes;
}
public Collection<Modification> normalizeModifications(Collection<Modification> modifications) throws Exception {
Collection<Modification> normalizedModifications = new ArrayList<Modification>();
for (Modification modification : modifications) {
int type = modification.getType();
Attribute attribute = modification.getAttribute();
String name = normalizeAttributeName(attribute.getName());
switch (type) {
case Modification.ADD:
log.debug("add: " + name);
break;
case Modification.DELETE:
log.debug("delete: " + name);
break;
case Modification.REPLACE:
log.debug("replace: " + name);
break;
}
Attribute normalizedAttribute = new Attribute(name);
normalizedAttribute.addValues(attribute.getValues());
Modification normalizedModification = new Modification(type, normalizedAttribute);
normalizedModifications.add(normalizedModification);
}
return normalizedModifications;
}
public boolean isOperational(String attributeName) {
AttributeType attributeType = getAttributeType(attributeName);
return attributeType != null && attributeType.isOperational();
}
public AttributeSyntax getAttributeSyntax(String oid) {
return AttributeSyntaxUtil.getAttributeSyntax(oid);
}
}