/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.isis.objectstore.jdo.datanucleus.persistence.spi; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; import java.util.List; import java.util.UUID; import javax.jdo.annotations.IdentityType; import javax.jdo.identity.ByteIdentity; import javax.jdo.identity.IntIdentity; import javax.jdo.identity.LongIdentity; import javax.jdo.identity.ObjectIdentity; import javax.jdo.identity.StringIdentity; import org.datanucleus.identity.DatastoreId; import org.apache.isis.core.metamodel.adapter.oid.RootOid; import org.apache.isis.core.metamodel.spec.ObjectSpecId; import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.core.metamodel.specloader.SpecificationLoader; import org.apache.isis.core.runtime.system.context.IsisContext; import org.apache.isis.core.runtime.system.session.IsisSessionFactory; import org.apache.isis.objectstore.jdo.metamodel.facets.object.persistencecapable.JdoPersistenceCapableFacet; public final class JdoObjectIdSerializer { private static final char SEPARATOR = '_'; private JdoObjectIdSerializer(){} public static class Exception extends RuntimeException { private static final long serialVersionUID = 1L; public Exception(final java.lang.Exception ex) { super(ex); } } public static String toOidIdentifier(final Object jdoOid) { // // @javax.jdo.annotations.PersistenceCapable(identityType = IdentityType.APPLICATION) // if(jdoOid instanceof javax.jdo.identity.ByteIdentity) { return "b" + SEPARATOR + jdoOid; } if(jdoOid instanceof javax.jdo.identity.IntIdentity) { return "i" + SEPARATOR + jdoOid; } if(jdoOid instanceof javax.jdo.identity.StringIdentity) { return "s" + SEPARATOR + jdoOid; } if(jdoOid instanceof javax.jdo.identity.LongIdentity) { return "l" + SEPARATOR + jdoOid; } if(jdoOid instanceof javax.jdo.identity.ObjectIdentity) { final javax.jdo.identity.ObjectIdentity id = (ObjectIdentity) jdoOid; final Object keyAsObject = id.getKeyAsObject(); // UUID support if(keyAsObject instanceof UUID) { final UUID uuid = (UUID) keyAsObject; return "u" + SEPARATOR + uuid.toString(); } } if(jdoOid instanceof DatastoreId) { // // prettier handling of common datatypes if possible // final DatastoreId dnOid = (DatastoreId) jdoOid; final Object keyValue = dnOid.getKeyAsObject(); if(false) { // // 1.8.0 original handling, appending a prefix "L_" or whatever // // if required by user community, we could add a property in isis.properties to enable if requested. // if(keyValue instanceof String) { return "S" + SEPARATOR + keyValue; } if(keyValue instanceof Long) { return "L" + SEPARATOR + keyValue; } if(keyValue instanceof BigInteger) { return "B" + SEPARATOR + keyValue; } if(keyValue instanceof Integer) { return "I" + SEPARATOR + keyValue; } } else { if( keyValue instanceof String || keyValue instanceof Long || keyValue instanceof BigDecimal || // 1.8.0 did not support BigDecimal keyValue instanceof BigInteger || keyValue instanceof Integer) { // no separator return "" + keyValue; } } } // the JDO spec (5.4.3) requires that OIDs are serializable toString and // recreatable through the constructor return jdoOid.getClass().getName() + SEPARATOR + jdoOid.toString(); } private static List<String> dnPrefixes = Arrays.asList("S", "I", "L", "M", "B"); public static Object toJdoObjectId(final RootOid oid) { final String idStr = oid.getIdentifier(); final int separatorIdx = idStr.indexOf(SEPARATOR); final ObjectSpecification spec = getSpecificationLoader().lookupBySpecId(oid.getObjectSpecId()); final JdoPersistenceCapableFacet jdoPcFacet = spec.getFacet(JdoPersistenceCapableFacet.class); if(separatorIdx != -1) { // behaviour for OIDs as of 1.8.0 and previously final String distinguisher = idStr.substring(0, separatorIdx); final String keyStr = idStr.substring(separatorIdx + 1); final boolean isApplicationIdentity = isApplicationIdentity(jdoPcFacet); if("s".equals(distinguisher)) { if (isApplicationIdentity) { return keyStr; } else { return new StringIdentity(objectTypeClassFor(oid), keyStr); } } else if("i".equals(distinguisher)) { if(isApplicationIdentity) { return Integer.parseInt(keyStr); } else { return new IntIdentity(objectTypeClassFor(oid), keyStr); } } else if("l".equals(distinguisher)) { if(isApplicationIdentity) { return Long.parseLong(keyStr); } else { return new LongIdentity(objectTypeClassFor(oid), keyStr); } } else if("b".equals(distinguisher)) { if(isApplicationIdentity) { return Byte.parseByte(keyStr); } else { return new ByteIdentity(objectTypeClassFor(oid), keyStr); } } else if("u".equals(distinguisher)) { if(isApplicationIdentity) { return UUID.fromString(keyStr); } else { return new ObjectIdentity(objectTypeClassFor(oid), UUID.fromString(keyStr)); } } if(dnPrefixes.contains(distinguisher)) { return keyStr + "[OID]" + spec.getFullIdentifier(); } final String clsName = distinguisher; try { final Class<?> cls = Thread.currentThread().getContextClassLoader().loadClass(clsName); final Constructor<?> cons = cls.getConstructor(String.class); final Object dnOid = cons.newInstance(keyStr); return dnOid.toString(); } catch (ClassNotFoundException | IllegalArgumentException | InstantiationException | IllegalAccessException | SecurityException | InvocationTargetException | NoSuchMethodException e) { throw new JdoObjectIdSerializer.Exception(e); } } else { // there was no separator, so this identifier must have been for // @javax.jdo.annotations.PersistenceCapable(identityType = IdentityType.DATASTORE) // for one of the common types (prettier handling) return idStr + "[OID]" + spec.getFullIdentifier(); } } protected static boolean isApplicationIdentity(final JdoPersistenceCapableFacet jdoPcFacet) { return jdoPcFacet != null && jdoPcFacet.getIdentityType() == IdentityType.APPLICATION; } private static Class<?> objectTypeClassFor(final RootOid oid) { final ObjectSpecId objectSpecId = oid.getObjectSpecId(); final ObjectSpecification spec = getSpecificationLoader().lookupBySpecId(objectSpecId); final Class<?> correspondingClass = spec.getCorrespondingClass(); return correspondingClass; } private static SpecificationLoader getSpecificationLoader() { return getIsisSessionFactory().getSpecificationLoader(); } static IsisSessionFactory getIsisSessionFactory() { return IsisContext.getSessionFactory(); } }