blob: 6fee9746a00ae0c4226a5e1b7996e62b63c4cbca [file] [log] [blame]
Thomas Vachuska3afbc7f2016-02-01 15:55:38 -08001/*
2 * Copyright 2014-2016 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.net;
17
18import com.google.common.annotations.Beta;
19import org.onlab.util.ItemNotFoundException;
20import org.onosproject.net.driver.Behaviour;
21import org.onosproject.net.driver.Driver;
22import org.onosproject.net.driver.DriverData;
23import org.onosproject.net.driver.DriverService;
24import org.onosproject.net.driver.Projectable;
25import org.onosproject.net.provider.ProviderId;
26import org.slf4j.Logger;
27import org.slf4j.LoggerFactory;
28
29import java.util.Set;
30
31import static com.google.common.base.Preconditions.checkState;
32
33/**
34 * Base model entity, capable of being extended via projection mechanism.
35 */
36@Beta
37public abstract class AbstractProjectableModel extends AbstractModel implements Projectable {
38
39 private static Logger log = LoggerFactory.getLogger(AbstractProjectableModel.class);
40
41 protected static final String NO_DRIVER_SERVICE = "Driver service not bound yet";
42 protected static final String NO_DRIVER = "Driver has not been bound to %s";
43
44 // Static reference to the driver service; injected via setDriverService
45 private static DriverService driverService;
46
47 private Driver driver;
48
49 // For serialization
50 public AbstractProjectableModel() {
51 }
52
53 /**
54 * Creates a model entity attributed to the specified provider and
55 * optionally annotated.
56 *
57 * @param providerId identity of the provider
58 * @param annotations optional key/value annotations
59 */
60 public AbstractProjectableModel(ProviderId providerId, Annotations[] annotations) {
61 super(providerId, annotations);
62 }
63
64 /**
65 * Injects the driver service reference for use during projections into
66 * various behaviours.
67 * <p>
68 * This is a privileged call; unauthorized invocations will result in
69 * illegal state exception
70 *
71 * @param key opaque admin key object
72 * @param driverService injected driver service
73 * @throws IllegalStateException when invoked sans authorization
74 */
75 public static void setDriverService(Object key, DriverService driverService) {
76 // TODO: Rework this once we have means to enforce access to admin services in general
77 checkState(AbstractProjectableModel.driverService == key, "Unauthorized invocation");
78 AbstractProjectableModel.driverService = driverService;
79 }
80
81 /**
82 * Returns the currently bound driver service reference.
83 *
84 * @return driver service
85 */
86 protected static DriverService driverService() {
87 return driverService;
88 }
89
90 /**
91 * Returns the currently bound driver or null of no driver is bound.
92 *
93 * @return bound driver; null if none
94 */
95 protected Driver driver() {
96 return driver;
97 }
98
99 @Override
100 public <B extends Behaviour> B as(Class<B> projectionClass) {
101 checkState(driverService != null, NO_DRIVER_SERVICE);
102 if (driver == null) {
103 driver = locateDriver();
104 }
105 checkState(driver != null, NO_DRIVER, this);
106 return driver.createBehaviour(asData(), projectionClass);
107 }
108
109 @Override
110 public <B extends Behaviour> boolean is(Class<B> projectionClass) {
111 checkState(driverService != null, NO_DRIVER_SERVICE);
112 if (driver == null) {
113 driver = locateDriver();
114 }
115 checkState(driver != null, "Driver has not been bound to %s", this);
116 return driver.hasBehaviour(projectionClass);
117 }
118
119 /**
120 * Locates the driver to be used by this entity.
121 * <p>
122 * The default implementation derives the driver based on the {@code driver}
123 * annotation value.
124 *
125 * @return driver for alternate projections of this model entity or null
126 * if no driver is expected or driver is not found
127 */
128 protected Driver locateDriver() {
129 String driverName = annotations().value(AnnotationKeys.DRIVER);
130 if (driverName != null) {
131 try {
132 return driverService.getDriver(driverName);
133 } catch (ItemNotFoundException e) {
134 log.warn("Driver {} not found.", driverName);
135 }
136 }
137 return null;
138 }
139
140 /**
141 * Returns self as an immutable driver data instance.
142 *
143 * @return self as driver data
144 */
145 protected DriverData asData() {
146 return new AnnotationDriverData();
147 }
148
149
150 /**
151 * Projection of the parent entity as a driver data entity.
152 */
153 protected class AnnotationDriverData implements DriverData {
154 @Override
155 public Driver driver() {
156 return driver;
157 }
158
159 @Override
160 public DeviceId deviceId() {
161 throw new UnsupportedOperationException("Entity not a device");
162 }
163
164 @Override
165 public MutableAnnotations set(String key, String value) {
166 throw new UnsupportedOperationException("Entity is immutable");
167 }
168
169 @Override
170 public MutableAnnotations clear(String... keys) {
171 throw new UnsupportedOperationException("Entity is immutable");
172 }
173
174 @Override
175 public Set<String> keys() {
176 return annotations().keys();
177 }
178
179 @Override
180 public String value(String key) {
181 return annotations().value(key);
182 }
183 }
184
185}