/* * Copyright 2016 Realm 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 io.realm; import java.util.List; import io.realm.internal.ObserverPairList; import io.realm.internal.PendingRow; import io.realm.internal.Row; import io.realm.internal.OsObject; import io.realm.internal.UncheckedRow; /** * This implements {@code RealmObjectProxy} interface, to eliminate copying logic between * {@link RealmObject} and {@link DynamicRealmObject}. */ public final class ProxyState<E extends RealmModel> implements PendingRow.FrontEnd { static class RealmChangeListenerWrapper<T extends RealmModel> implements RealmObjectChangeListener<T> { private final RealmChangeListener<T> listener; RealmChangeListenerWrapper(RealmChangeListener<T> listener) { if (listener == null) { throw new IllegalArgumentException("Listener should not be null"); } this.listener = listener; } @Override public void onChange(T object, ObjectChangeSet changes) { listener.onChange(object); } @Override public boolean equals(Object obj) { return obj instanceof RealmChangeListenerWrapper && listener == ((RealmChangeListenerWrapper) obj).listener; } @Override public int hashCode() { return listener.hashCode(); } } private static class QueryCallback implements ObserverPairList.Callback<OsObject.ObjectObserverPair> { @Override public void onCalled(OsObject.ObjectObserverPair pair, Object observer) { //noinspection unchecked pair.onChange((RealmModel) observer, null); } } private E model; // true only while executing the constructor of the enclosing proxy object private boolean underConstruction = true; private Row row; private OsObject osObject; private BaseRealm realm; private boolean acceptDefaultValue; private List<String> excludeFields; private ObserverPairList<OsObject.ObjectObserverPair> observerPairs = new ObserverPairList<OsObject.ObjectObserverPair>(); private static QueryCallback queryCallback = new QueryCallback(); public ProxyState() {} public ProxyState(E model) { this.model = model; } public BaseRealm getRealm$realm() { return realm; } public void setRealm$realm(BaseRealm realm) { this.realm = realm; } public Row getRow$realm() { return row; } public void setRow$realm(Row row) { this.row = row; } public boolean getAcceptDefaultValue$realm() { return acceptDefaultValue; } public void setAcceptDefaultValue$realm(boolean acceptDefaultValue) { this.acceptDefaultValue = acceptDefaultValue; } public List<String> getExcludeFields$realm() { return excludeFields; } public void setExcludeFields$realm(List<String> excludeFields) { this.excludeFields = excludeFields; } /** * Notifies all registered listeners. */ private void notifyQueryFinished() { observerPairs.foreach(queryCallback); } public void addChangeListener(RealmObjectChangeListener<E> listener) { if (row instanceof PendingRow) { observerPairs.add(new OsObject.ObjectObserverPair<E>(model, listener)); } else if (row instanceof UncheckedRow) { registerToObjectNotifier(); if (osObject != null) { osObject.addListener(model, listener); } } } public void removeChangeListener(RealmObjectChangeListener<E> listener) { if (osObject != null) { osObject.removeListener(model, listener); } else { observerPairs.remove(model, listener); } } public void removeAllChangeListeners() { if (osObject != null) { osObject.removeListener(model); } else { observerPairs.clear(); } } public boolean isUnderConstruction() { return underConstruction; } public void setConstructionFinished() { underConstruction = false; // Only used while construction. excludeFields = null; } private void registerToObjectNotifier() { if (realm.sharedRealm == null || realm.sharedRealm.isClosed() || !row.isAttached()) { return; } if (osObject == null) { osObject = new OsObject(realm.sharedRealm, (UncheckedRow) row); osObject.setObserverPairs(observerPairs); // We should never need observerPairs after pending row returns. observerPairs = null; } } public boolean isLoaded() { return !(row instanceof PendingRow); } public void load() { if (row instanceof PendingRow) { ((PendingRow) row).executeQuery(); } } @Override public void onQueryFinished(Row row) { this.row = row; // getTable should return a non-null table since the row should always be valid here. notifyQueryFinished(); if (row.isAttached()) { registerToObjectNotifier(); } } }