@SuppressWarnings("unchecked") protected Object unwrap(Object node) { Object result = node; if (node instanceof Map) { Map<String, Object> cast = (Map<String, Object>) node; ORecordId id; if (cast.containsKey("id")) { id = new ORecordId((String) cast.get("id")); cast.remove("id"); } else id = new ORecordId(); ODocument real; if (id.isNew()) { if (cast.containsKey("class")) { real = new ODocument((String) cast.get("class")); cast.remove("class"); } else throw new RuntimeException( "Unknown class in newly created ODocument. Please provide 'class' property in every new object."); } else real = new ODocument(id); for (String key : cast.keySet()) real.field(key, unwrap(cast.get(key))); result = real; } else if (node instanceof List) { List<Object> cast = (List<Object>) node; for (int i = 0; i < cast.size(); i++) cast.set(i, unwrap(cast.get(i))); } return result; }
public void executeSaveRecord( final ORecordInternal<?> iRecord, String iClusterName, final int iVersion, final byte iRecordType) { checkOpeness(); if (!iRecord.isDirty()) return; final ORecordId rid = (ORecordId) iRecord.getIdentity(); if (rid == null) throw new ODatabaseException( "Cannot create record because it has no identity. Probably is not a regular record or contains projections of fields rather than a full record"); setCurrentDatabaseinThreadLocal(); try { final boolean wasNew = rid.isNew(); // STREAM.LENGTH == 0 -> RECORD IN STACK: WILL BE SAVED AFTER byte[] stream = iRecord.toStream(); final boolean isNew = rid.isNew(); if (isNew) // NOTIFY IDENTITY HAS CHANGED iRecord.onBeforeIdentityChanged(rid); else if (stream.length == 0) // ALREADY CREATED AND WAITING FOR THE RIGHT UPDATE (WE'RE IN A GRAPH) return; if (isNew && rid.clusterId < 0) rid.clusterId = iClusterName != null ? getClusterIdByName(iClusterName) : getDefaultClusterId(); if (rid.clusterId > -1 && iClusterName == null) iClusterName = getClusterNameById(rid.clusterId); if (stream != null && stream.length > 0) { if (wasNew) { // CHECK ACCESS ON CLUSTER checkSecurity(ODatabaseSecurityResources.CLUSTER, ORole.PERMISSION_CREATE, iClusterName); if (callbackHooks(TYPE.BEFORE_CREATE, iRecord)) // RECORD CHANGED IN TRIGGER, REACQUIRE IT stream = iRecord.toStream(); } else { // CHECK ACCESS ON CLUSTER checkSecurity(ODatabaseSecurityResources.CLUSTER, ORole.PERMISSION_UPDATE, iClusterName); if (callbackHooks(TYPE.BEFORE_UPDATE, iRecord)) // RECORD CHANGED IN TRIGGER, REACQUIRE IT stream = iRecord.toStream(); } if (!iRecord.isDirty()) { // RECORD SAVED DURING PREVIOUS STREAMING PHASE: THIS HAPPENS FOR CIRCULAR REFERENCED // RECORDS // ADD/UPDATE IT IN CACHE IF IT'S ACTIVE getLevel1Cache().updateRecord(iRecord); return; } } // GET THE LATEST VERSION. IT COULD CHANGE BECAUSE THE RECORD COULD BE BEEN LINKED FROM OTHERS final int realVersion = iVersion == -1 || !mvcc ? -1 : iRecord.getVersion(); // SAVE IT final long result = underlying.save(rid, stream, realVersion, iRecord.getRecordType()); if (isNew) { // UPDATE INFORMATION: CLUSTER ID+POSITION ((ORecordId) iRecord.getIdentity()).copyFrom(rid); // NOTIFY IDENTITY HAS CHANGED iRecord.onAfterIdentityChanged(iRecord); // UPDATE INFORMATION: CLUSTER ID+POSITION iRecord.fill(rid, 0, stream, stream == null || stream.length == 0); } else { // UPDATE INFORMATION: VERSION iRecord.fill(rid, (int) result, stream, stream == null || stream.length == 0); } callbackHooks(wasNew ? TYPE.AFTER_CREATE : TYPE.AFTER_UPDATE, iRecord); if (stream != null && stream.length > 0) // ADD/UPDATE IT IN CACHE IF IT'S ACTIVE getLevel1Cache().updateRecord(iRecord); } catch (OException e) { // RE-THROW THE EXCEPTION throw e; } catch (Throwable t) { // WRAP IT AS ODATABASE EXCEPTION throw new ODatabaseException( "Error on saving record in cluster #" + iRecord.getIdentity().getClusterId(), t); } }