/*
* $Id: FileRealm.java,v 1.12 2002/09/16 08:05:06 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.server.file;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Permission;
import anvil.java.util.BindingEnumeration;
import anvil.core.Any;
import anvil.core.Array;
import anvil.java.util.Hashlist;
import anvil.util.Mapping;
import anvil.util.Map;
import anvil.util.Conversions;
import anvil.server.RealmPreferences;
import anvil.server.Zone;
import anvil.server.Citizen;
import anvil.server.Realm;
import anvil.server.Tribe;
import anvil.server.Citizen;
import anvil.server.Preferences;
import anvil.server.PolicyPreferences;
import anvil.server.ConfigurationError;
import anvil.server.Realm;
import anvil.server.Tribe;
import anvil.server.Citizen;
import anvil.server.OperationFailedException;
/**
* class FileRealm
*
* @author: Jani Lehtim�ki
*/
public class FileRealm implements Realm
{
private Zone _zone;
private String _name;
private Map _map = new Map();
private Hashlist _citizens = new Hashlist();
private Hashlist _tribes = new Hashlist();
private Hashlist _entities = new Hashlist();
private File _dir;
private FileTribe _root;
private boolean _copyonget = false;
private boolean _copyonset = false;
private int _modcount = 0;
private int _maxmodcount = 100;
private File _index;
private long _lastmodified = -1;
private int _nextid = 1;
public FileRealm()
{
}
public String toString()
{
return "FileRealm("+_name+"@"+_dir+")";
}
protected synchronized int getNextId()
{
return _nextid++;
}
public Zone getZone()
{
return _zone;
}
public boolean copyOnGet()
{
return _copyonget;
}
public boolean copyOnSet()
{
return _copyonset;
}
public int getMaxModifications()
{
return _maxmodcount;
}
void addMapping(Object a, Object b)
{
load();
_map.add(a, b);
save(false);
}
void removeMapping(Object a, Object b)
{
load();
_map.remove(a, b);
save(false);
}
void removeMappings(Object a)
{
load();
_map.remove(a);
if (a instanceof FileCitizen) {
FileCitizen citizen = (FileCitizen)a;
_entities.remove(new Integer(citizen.getId()));
_citizens.remove(citizen.getName());
} else {
FileTribe tribe = (FileTribe)a;
_entities.remove(new Integer(tribe.getId()));
_tribes.remove(tribe.getName());
if (tribe == _root) {
_root = null;
}
}
save(false);
}
boolean isMapped(Object o, Class elemcls, boolean left, boolean right)
{
load();
return _map.isMapped(o, elemcls, left, right);
}
Object[] getMappings(Object o, Class elemcls, boolean left, boolean right)
{
load();
return _map.get(o, elemcls, left, right);
}
protected synchronized void load()
{
if (!_index.exists()) {
return;
}
if (_index.lastModified() <= _lastmodified) {
return;
}
_entities.clear();
_citizens.clear();
_tribes.clear();
_map.clear();
_nextid = 0;
FileInputStream in = null;
try {
in = new FileInputStream(_index);
LineNumberReader reader = new LineNumberReader(new InputStreamReader(in));
for(;;) {
String str = reader.readLine();
if (str == null) {
break;
}
if (str.length() == 0) {
continue;
}
int i = str.indexOf(':');
if (i == -1) {
i = str.indexOf(' ');
if (i == -1) {
continue;
}
}
String command = str.substring(0, i).trim();
str = str.substring(i+1);
try {
switch(command.charAt(0)) {
case '#':
{
continue;
}
case 'r':
{
_root = (FileTribe)_entities.get(new Integer(str));
}
break;
case 't':
{
String[] args = Preferences.parseValues(str);
if (args.length >= 2) {
int id = Integer.parseInt(args[0]);
if (id >= _nextid) {
_nextid = id+1;
}
String name = Conversions.URLDecode(args[1]);
Tribe tribe = createTribe(id, name);
_entities.put(new Integer(id), tribe);
_tribes.put(name, tribe);
}
}
break;
case 'c':
{
String[] args = Preferences.parseValues(str);
if (args.length >= 3) {
int id = Integer.parseInt(args[0]);
if (id >= _nextid) {
_nextid = id+1;
}
String name = Conversions.URLDecode(args[1]);
String crendentials = Conversions.URLDecode(args[2]);
Citizen citizen = createCitizen(id, name, crendentials);
_entities.put(new Integer(id), citizen);
_citizens.put(name, citizen);
}
}
break;
case 'p':
{
String[] args = Preferences.parseValues(str);
int n = args.length;
if (n >= 2) {
int id = Integer.parseInt(args[0]);
FileEntity ent = (FileEntity)_entities.get(new Integer(id));
if (ent != null) {
try {
String[] s = new String[n-1];
System.arraycopy(args, 1, s, 0, n-1);
Permission perm = PolicyPreferences.createPermission(s);
if (perm != null) {
ent.addPermission(perm);
}
} catch (Throwable t) {
_zone.log().error(t);
}
}
}
}
break;
case 'm':
{
String[] args = Preferences.parseValues(str);
if (args.length >= 2) {
String ak = args[0];
String bk = args[1];
Object a = _entities.get(new Integer(ak));
Object b = _entities.get(new Integer(bk));
_map.add(a, b);
}
}
}
} catch (NumberFormatException e) {
}
}
in.close();
} catch (IOException e) {
_zone.log().error(e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
}
}
_lastmodified = _index.lastModified();
}
public synchronized void save(boolean forcesave)
{
_modcount++;
if (!forcesave) {
if ((_modcount % _maxmodcount) != 0) {
return;
}
}
Iterator iter = _entities.iterator();
while(iter.hasNext()) {
FileEntity ent = (FileEntity)iter.next();
ent.commit();
}
FileOutputStream out = null;
try {
out = new FileOutputStream(_index);
iter = _entities.iterator();
while(iter.hasNext()) {
FileEntity ent = (FileEntity)iter.next();
ent.commit();
ent.write(out);
PermissionCollection pc = ent.getPermissions();
if (pc != null) {
byte[] idstr = Conversions.getBytes(Integer.toString(ent.getId()));
Enumeration enum = pc.elements();
while(enum.hasMoreElements()) {
Permission perm = (Permission)enum.nextElement();
out.write('p');
out.write(':');
out.write(idstr);
out.write(',');
out.write(' ');
out.write('"');
out.write(Conversions.getBytes(perm.getClass().getName()));
out.write('"');
out.write(',');
out.write(' ');
out.write('"');
out.write(Conversions.getBytes(perm.getName()));
out.write('"');
out.write(',');
out.write(' ');
out.write('"');
out.write(Conversions.getBytes(perm.getActions()));
out.write('"');
out.write('\n');
}
}
}
iter = _map.iterator();
while(iter.hasNext()) {
Mapping map = (Mapping)iter.next();
out.write('m');
out.write(':');
out.write(' ');
out.write(Conversions.getBytes(Integer.toString(map.getLeft().hashCode())));
out.write(',');
out.write(' ');
out.write(Conversions.getBytes(Integer.toString(map.getRight().hashCode())));
out.write('\n');
}
out.write('r');
out.write(':');
out.write(' ');
if (_root != null) {
out.write(Conversions.getBytes(Integer.toString(_root.hashCode())));
} else {
out.write('0');
}
out.write('\n');
out.close();
} catch (IOException e) {
_zone.log().error(e);
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
}
}
_lastmodified = _index.lastModified();
}
public void initialize(RealmPreferences prefs)
{
_name = prefs.getName();
_zone = prefs.getParent();
String dir = (String)prefs.getPreference("dir");
if (dir == null) {
throw new ConfigurationError("Required parameter 'dir' missing from realm preferences");
}
_dir = new File(dir);
_index = new File(_dir, "index");
_copyonget = prefs.getBooleanPreference("copyonget", false);
_copyonset = prefs.getBooleanPreference("copyonset", false);
_maxmodcount = prefs.getIntPreference("maxmodifications", 1);
if (_maxmodcount < 1) {
_maxmodcount = 1;
}
_zone.log().info("Realm " + this + " initialized");
}
public Citizen getAnonymousCitizen()
{
return null;
}
public Citizen getCitizen(String username)
{
load();
return (Citizen)_citizens.get(username);
}
public Tribe getTribe(String name)
{
load();
return (Tribe)_tribes.get(name);
}
public Citizen[] searchCitizenByVariable(String variable, String value)
{
ArrayList list = new ArrayList();
Enumeration enum = _citizens.elements();
while(enum.hasMoreElements()) {
FileCitizen citizen = (FileCitizen)enum.nextElement();
Any data = citizen.getVariable(variable);
if (data.toString().equals(value)) {
list.add(citizen);
}
}
return (Citizen[])list.toArray(new Citizen[list.size()]);
}
public synchronized Citizen createCitizen(int id, String name, String crendentials)
{
FileCitizen citizen = new FileCitizen(this, new File(_dir, id+".data"),
id, name, crendentials);
_entities.put(new Integer(id), citizen);
_citizens.put(name, citizen);
return citizen;
}
public synchronized Citizen createCitizen(String name, String credentials)
{
load();
Citizen citizen = createCitizen(getNextId(), name, credentials);
save(false);
return citizen;
}
public synchronized Citizen createCitizen(String name, String credentials, String[][] params)
{
load();
Citizen citizen = createCitizen(getNextId(), name, credentials);
if (params != null) {
for (int i=0,l=params.length; i<l; i++) {
citizen.setVariable(params[i][0], Any.create(params[i][1]));
}
}
save(false);
return citizen;
}
public synchronized Tribe createTribe(int id, String name)
{
FileTribe tribe = new FileTribe(this, new File(_dir, id+".data"), id, name);
_entities.put(new Integer(id), tribe);
return tribe;
}
public synchronized Tribe createTribe(String name)
{
load();
Tribe tribe = createTribe(getNextId(), name);
save(false);
return tribe;
}
public Tribe getRoot()
{
load();
return _root;
}
public synchronized void setRoot(Tribe tribe)
{
load();
_root = (FileTribe)tribe;
save(false);
}
public void stop()
{
save(true);
_map.clear();
_citizens.clear();
_entities.clear();
_root = null;
_zone.log().info("Realm " + this + " stopped");
}
}