/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.persistence; import java.awt.Color; import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.beans.IntrospectionException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.json.JSONException; import com.servoy.j2db.server.shared.IUnresolvedUUIDResolver; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.Internalize; import com.servoy.j2db.util.PersistHelper; import com.servoy.j2db.util.ServoyJSONObject; import com.servoy.j2db.util.TreeBidiMap; import com.servoy.j2db.util.UUID; import com.servoy.j2db.util.Utils; /** * @author jcompagner * */ public abstract class AbstractPersistFactory implements IPersistFactory { protected final TreeBidiMap<UUID, Integer> uuid_element_id_map; //uuid->element_id private ContentSpec contentSpec = null; /** * */ public AbstractPersistFactory() { super(); uuid_element_id_map = new TreeBidiMap<UUID, Integer>(); } public abstract void initClone(IPersist clone, IPersist objToClone, boolean flattenOverrides) throws RepositoryException; public int getElementIdForUUID(UUID uuid) throws RepositoryException { Integer element_id = uuid_element_id_map.get(uuid); if (element_id != null) { return element_id.intValue(); } int resolved = resolveIdForElementUuid(uuid); element_id = new Integer(resolved); if (!uuid_element_id_map.containsKey(uuid) && !uuid_element_id_map.containsValue(element_id)) { uuid_element_id_map.put(uuid, element_id); } return resolved; } public abstract int resolveIdForElementUuid(UUID id) throws RepositoryException; /* * id from uuid lookup methods */ public int getElementIdForUUIDString(String uuid) throws RepositoryException { int id = 0; if (uuid != null) { uuid = uuid.trim(); if (uuid.indexOf('-') > 0) { // This is really a UUID. Convert it to an element id. return getElementIdForUUID(UUID.fromString(uuid)); } else { // This is not a UUID but a degenerate value; parse it and ensure it is less than or equal to 0. try { id = Integer.parseInt(uuid); if (id > 0) { throw new RepositoryException("invalid degenerate UUID value " + id); } } catch (NumberFormatException e) { throw new RepositoryException("invalid UUID format " + uuid); } } } return id; } /** * Create a repositoy object like Form,fields,portals,beans,etc. * * @param parent the parent * @param objectTypeId the type * @param elementId the element_id for creation * @return the created object */ public IPersist createObject(ISupportChilds parent, int objectTypeId, int elementId, UUID uuid) throws RepositoryException { IPersist object = null; switch (objectTypeId) { case IRepository.FORMS : object = new Form(parent, elementId, uuid); break; case IRepository.LAYOUTCONTAINERS : object = new LayoutContainer(parent, elementId, uuid); break; case IRepository.GRAPHICALCOMPONENTS : object = new GraphicalComponent(parent, elementId, uuid); break; case IRepository.FIELDS : object = new Field(parent, elementId, uuid); break; case IRepository.PORTALS : object = new Portal(parent, elementId, uuid); break; case IRepository.TABPANELS : object = new TabPanel(parent, elementId, uuid); break; case IRepository.TABS : object = new Tab(parent, elementId, uuid); break; case IRepository.SHAPES : object = new Shape(parent, elementId, uuid); break; case IRepository.BEANS : object = new Bean(parent, elementId, uuid); break; case IRepository.RELATIONS : object = new Relation(parent, elementId, uuid); break; case IRepository.METHODS : object = new ScriptMethod(parent, elementId, uuid); break; case IRepository.SCRIPTCALCULATIONS : object = new ScriptCalculation(parent, elementId, uuid); break; case IRepository.AGGREGATEVARIABLES : object = new AggregateVariable(parent, elementId, uuid); break; case IRepository.VALUELISTS : object = new ValueList(parent, elementId, uuid); break; case IRepository.SCRIPTVARIABLES : object = new ScriptVariable(parent, elementId, uuid); break; case IRepository.RELATION_ITEMS : object = new RelationItem(parent, elementId, uuid); break; case IRepository.RECTSHAPES : object = new RectShape(parent, elementId, uuid); break; case IRepository.PARTS : object = new Part(parent, elementId, uuid); break; case IRepository.TABLENODES : object = new TableNode(parent, elementId, uuid); break; case IRepository.MEDIA : object = new Media(parent, elementId, uuid); break; case IRepository.WEBCOMPONENTS : object = new WebComponent(parent, elementId, uuid); break; case IRepository.SOLUTIONS : case IRepository.STYLES : case IRepository.TEMPLATES : object = createRootObject(elementId); break; default : throw new RepositoryException("cannot create object with type id=" + objectTypeId + ", type does not exist"); //$NON-NLS-1$ //$NON-NLS-2$ } // Save the uuid to element id mapping. if (!uuid_element_id_map.containsKey(uuid)) { uuid_element_id_map.put(uuid, new Integer(elementId)); } return object; } protected abstract IPersist createRootObject(int elementId) throws RepositoryException; /** * Converter method to convert String in object * * @param type_id the type * @param s the string * @return the object */ public Object convertArgumentStringToObject(int typeId, String s) throws RepositoryException { Object retval = null; switch (typeId) { case IRepository.DIMENSION : retval = PersistHelper.createDimension(s); break; case IRepository.ELEMENTS : retval = Integer.valueOf(getElementIdForUUIDString(s)); break; case IRepository.BLOBS : case IRepository.INTEGER : retval = Integer.valueOf(Utils.getAsInteger(s)); break; case IRepository.BORDER : retval = s; break; case IRepository.COLOR : retval = PersistHelper.createColor(s); break; case IRepository.POINT : retval = PersistHelper.createPoint(s); break; case IRepository.INSETS : retval = PersistHelper.createInsets(s); break; case IRepository.STRING : case IRepository.STYLES : case IRepository.TEMPLATES : case IRepository.SERVERS : case IRepository.TABLES : case IRepository.DATASOURCES : retval = s; break; case IRepository.FONT : retval = s;//PersistHelper.createFont(s); fonts must be created in client break; case IRepository.BOOLEAN : retval = Boolean.valueOf(Utils.getAsBoolean(s)); break; case IRepository.JSON : try { retval = new ServoyJSONObject(s, false); } catch (JSONException ex) { Debug.error(ex); } break; default : throw new RepositoryException("type with id=" + typeId + " does not exist"); } retval = Internalize.intern(retval); return retval; } public Map<String, Method> getSettersViaIntrospection(Object obj) throws IntrospectionException { return RepositoryHelper.getSettersViaIntrospection(obj); } public ContentSpec getContentSpec() throws RepositoryException { if (contentSpec == null) { synchronized (this) { contentSpec = loadContentSpec(); } } return contentSpec; } public synchronized void flushContentSpec() { contentSpec = null; } protected abstract ContentSpec loadContentSpec() throws RepositoryException; public String convertObjectToArgumentString(int typeId, Object obj) throws RepositoryException { return convertObjectToArgumentString(typeId, obj, -1, -1, -1, null); } /** * Converter method to convert object in string * * @param type_id the type * @param obj the object * @return the string */ public String convertObjectToArgumentString(int typeId, Object obj, int elementId, int revision, int contentId, IUnresolvedUUIDResolver resolver) throws RepositoryException { if (obj == null) return null; String retval = null; switch (typeId) { case IRepository.BORDER : retval = (String)obj; break; case IRepository.INSETS : retval = PersistHelper.createInsetsString((Insets)obj); break; case IRepository.DIMENSION : retval = PersistHelper.createDimensionString((Dimension)obj); break; case IRepository.COLOR : retval = PersistHelper.createColorString((Color)obj); break; case IRepository.POINT : retval = PersistHelper.createPointString((Point)obj); break; case IRepository.FONT : retval = (String)obj; break; case IRepository.ELEMENTS : retval = getUUIDStringForElementId(((Integer)obj).intValue(), elementId, revision, contentId, resolver); break; case IRepository.STRING : case IRepository.INTEGER : case IRepository.BOOLEAN : case IRepository.STYLES : case IRepository.TEMPLATES : case IRepository.SERVERS : case IRepository.TABLES : case IRepository.DATASOURCES : case IRepository.BLOBS : case IRepository.JSON : retval = obj.toString(); break; default : throw new RepositoryException("type with id=" + typeId + " does not exist"); } return retval; } public String getUUIDStringForElementId(int id, int elementId, int revision, int contentId, IUnresolvedUUIDResolver resolver) throws RepositoryException { UUID uuid = getUUIDForElementId(id, elementId, revision, contentId, resolver); if (uuid != null) { return uuid.toString(); } return String.valueOf(id); } /* * uuid from id lookup methods */ public UUID getUUIDForElementId(int id, int elementId, int revision, int contentId, IUnresolvedUUIDResolver resolver) throws RepositoryException { if (id == IRepository.UNRESOLVED_ELEMENT) { if (resolver != null) { UUID uid = resolver.resolve(elementId, revision, contentId); if (uid != null) { return uid; } } return IRepository.UNRESOLVED_UUID; } if (id > 0) { UUID uuid = resolveUUIDForElementId(id); if (uuid == null) { uuid = uuid_element_id_map.getKey(new Integer(id)); } return uuid; } // This is a degenerate reference. return null; } public abstract UUID resolveUUIDForElementId(int id) throws RepositoryException; public static Map<Integer, Integer> resetUUIDSRecursively(IPersist persist, final IPersistFactory persistFactory, final boolean flagChanged) { final Map<Integer, Integer> updatedElementIds = new HashMap<Integer, Integer>(); persist.acceptVisitor(new IPersistVisitor() { public Object visit(IPersist o) { if (o instanceof AbstractBase) { ((AbstractBase)o).resetUUID(); try { int newElementID = persistFactory.getNewElementID(o.getUUID()); updatedElementIds.put(Integer.valueOf(o.getID()), Integer.valueOf(newElementID)); ((AbstractBase)o).setID(newElementID); if (flagChanged) o.flagChanged(); } catch (RepositoryException e) { Debug.log(e); } } return IPersistVisitor.CONTINUE_TRAVERSAL; } }); return updatedElementIds; } public void clearUUIDMap() { uuid_element_id_map.clear(); } }