ObservableContext.java
001 /*
002  * Copyright 2008-2016 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *     http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package griffon.core;
017 
018 import javax.annotation.Nonnull;
019 import javax.annotation.Nullable;
020 
021 import static griffon.util.GriffonNameUtils.requireNonBlank;
022 import static java.util.Objects.requireNonNull;
023 
024 /**
025  @author Andres Almiray
026  @since 2.5.0
027  */
028 public interface ObservableContext extends Context {
029     void addContextEventListener(@Nonnull ContextEventListener listener);
030 
031     void removeContextEventListener(@Nonnull ContextEventListener listener);
032 
033     @Nonnull
034     ContextEventListener[] getContextEventListeners();
035 
036     interface ContextEventListener {
037         void contextChanged(@Nonnull ContextEvent contextEvent);
038     }
039 
040     class ContextEvent {
041         private final Type type;
042         private final String key;
043         private final Object oldValue;
044         private final Object newValue;
045 
046         public ContextEvent(@Nonnull Type type, @Nonnull String key, @Nullable Object oldValue, @Nullable Object newValue) {
047             this.type = requireNonNull(type, "Argument 'type' must not be null");
048             this.key = requireNonBlank(key, "Argument 'key' must not be null");
049             this.oldValue = oldValue;
050             this.newValue = newValue;
051         }
052 
053         @Nonnull
054         public Type getType() {
055             return type;
056         }
057 
058         @Nonnull
059         public String getKey() {
060             return key;
061         }
062 
063         @Nullable
064         public Object getOldValue() {
065             return oldValue;
066         }
067 
068         @Nullable
069         public Object getNewValue() {
070             return newValue;
071         }
072 
073         @Override
074         public boolean equals(Object o) {
075             if (this == oreturn true;
076             if (o == null || getClass() != o.getClass()) return false;
077 
078             ContextEvent that = (ContextEvento;
079 
080             if (!key.equals(that.key)) return false;
081             if (newValue != null ? !newValue.equals(that.newValue: that.newValue != nullreturn false;
082             if (oldValue != null ? !oldValue.equals(that.oldValue: that.oldValue != nullreturn false;
083             if (type != that.typereturn false;
084 
085             return true;
086         }
087 
088         @Override
089         public int hashCode() {
090             int result = type.hashCode();
091             result = 31 * result + key.hashCode();
092             result = 31 * result + (oldValue != null ? oldValue.hashCode() 0);
093             result = 31 * result + (newValue != null ? newValue.hashCode() 0);
094             return result;
095         }
096 
097         @Override
098         public String toString() {
099             final StringBuilder sb = new StringBuilder("ContextEvent{");
100             sb.append("type=").append(type);
101             sb.append(", key='").append(key).append('\'');
102             sb.append(", oldValue=").append(oldValue);
103             sb.append(", newValue=").append(newValue);
104             sb.append('}');
105             return sb.toString();
106         }
107 
108         public enum Type {
109             ADD, REMOVE, UPDATE
110         }
111     }
112 }