/* * Copyright 2011 Future Systems, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.confdb.file; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.krakenapps.api.PrimitiveConverter; import org.krakenapps.api.PrimitiveParseCallback; import org.krakenapps.codec.UnsupportedTypeException; import org.krakenapps.confdb.Config; import org.krakenapps.confdb.ConfigCollection; import org.krakenapps.confdb.ConfigDatabase; import org.krakenapps.confdb.ConfigParser; class FileConfig implements Config { private ConfigDatabase db; private ConfigCollection col; private int id; private long rev; private long prevRev; private Object doc; private ConfigParser parser; public FileConfig(ConfigDatabase db, ConfigCollection col, int id, long rev, long prevRev, Object doc) { this(db, col, id, rev, prevRev, doc, null); } public FileConfig(ConfigDatabase db, ConfigCollection col, int id, long rev, long prevRev, Object doc, ConfigParser parser) { this.db = db; this.col = col; this.id = id; this.rev = rev; this.prevRev = prevRev; this.doc = doc; this.parser = parser; } @Override public ConfigDatabase getDatabase() { return db; } @Override public ConfigCollection getCollection() { return col; } @Override public int getId() { return id; } @Override public long getRevision() { return rev; } @Override public long getPrevRevision() { return prevRev; } @Override public Object getDocument() { return doc; } @Override public <T> T getDocument(Class<T> cls) { return getDocument(cls, null); } @SuppressWarnings("unchecked") @Override public <T> T getDocument(Class<T> cls, PrimitiveParseCallback callback) { if (parser != null) { Object o = parser.parse(doc, callback); if (o == null || cls.isAssignableFrom(o.getClass())) return (T) o; } return PrimitiveConverter.parse(cls, doc, callback); } @Override public void setDocument(Object doc) { this.doc = doc; } @Override public void update() { col.update(this); } @Override public void remove() { col.remove(this); } @Override public String toString() { return "id=" + id + ", rev=" + rev + ", prev=" + prevRev + ", doc=" + doc; } @Override public Config duplicate() { return new FileConfig(db, col, id, rev, prevRev, duplicateDoc(doc)); } @SuppressWarnings("unchecked") private Object duplicateDoc(Object doc) { if (doc == null) return null; if (doc instanceof Map) { Map<String, Object> m = (Map<String, Object>) doc; HashMap<String, Object> n = new HashMap<String, Object>(m.size()); for (Entry<String, Object> pair : m.entrySet()) { Object v = pair.getValue(); // fast path if (v == null) n.put(pair.getKey(), null); else if (v.getClass() == String.class) n.put(pair.getKey(), v); else n.put(pair.getKey(), duplicateDoc(v)); } return n; } else if (doc instanceof Collections) { Collection<Object> c = (Collection<Object>) doc; ArrayList<Object> n = new ArrayList<Object>(c.size()); for (Object o : c) n.add(duplicateDoc(o)); return n; } else if (doc.getClass().isArray()) { Class c = doc.getClass().getComponentType(); if (c == byte.class) { byte[] arr = (byte[]) doc; byte[] n = new byte[arr.length]; n = Arrays.copyOf(arr, arr.length); return n; } else if (c == int.class) { int[] arr = (int[]) doc; int[] n = new int[arr.length]; n = Arrays.copyOf(arr, arr.length); return n; } else if (c == double.class) { double[] arr = (double[]) doc; double[] n = new double[arr.length]; n = Arrays.copyOf(arr, arr.length); return n; } else if (c == float.class) { float[] arr = (float[]) doc; float[] n = new float[arr.length]; n = Arrays.copyOf(arr, arr.length); return n; } else if (c == boolean.class) { boolean[] arr = (boolean[]) doc; boolean[] n = new boolean[arr.length]; n = Arrays.copyOf(arr, arr.length); return n; } else if (c == char.class) { throw new UnsupportedTypeException("unsupported data type [" + c.getName() + "]"); } else if (c == long.class) { long[] arr = (long[]) doc; long[] n = new long[arr.length]; n = Arrays.copyOf(arr, arr.length); return n; } else if (c == short.class) { short[] arr = (short[]) doc; short[] n = new short[arr.length]; n = Arrays.copyOf(arr, arr.length); return n; } else { Object[] os = (Object[]) doc; Object[] n = new Object[os.length]; for (int i = 0; i < os.length; i++) n[i] = duplicateDoc(os[i]); return n; } } else return doc; } }