blob: cff824894845a57df78b72dda234df30b34af88c [file] [log] [blame]
Carmelo Cascone07d72712017-07-14 15:57:47 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Cascone07d72712017-07-14 15:57:47 -04003 *
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 */
16
17package org.onosproject.net.pi.model;
18
19import com.google.common.collect.ImmutableMap;
ghj0504520ec1a4202018-10-22 10:50:41 -070020import org.apache.commons.io.IOUtils;
Carmelo Cascone07d72712017-07-14 15:57:47 -040021import org.onosproject.net.driver.Behaviour;
22
Carmelo Cascone31d3e442017-07-18 16:58:51 -040023import java.io.IOException;
Carmelo Cascone07d72712017-07-14 15:57:47 -040024import java.io.InputStream;
Carmelo Cascone31d3e442017-07-18 16:58:51 -040025import java.net.URL;
ghj0504520ec1a4202018-10-22 10:50:41 -070026import java.nio.ByteBuffer;
27import java.util.ArrayList;
28import java.util.Arrays;
Carmelo Cascone07d72712017-07-14 15:57:47 -040029import java.util.Collection;
30import java.util.Map;
31import java.util.Optional;
32
Carmelo Cascone31d3e442017-07-18 16:58:51 -040033import static com.google.common.base.Preconditions.checkArgument;
Carmelo Cascone07d72712017-07-14 15:57:47 -040034import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Cascone31d3e442017-07-18 16:58:51 -040035import static java.lang.String.format;
Carmelo Cascone07d72712017-07-14 15:57:47 -040036
37/**
38 * Default pipeconf implementation.
39 */
40public final class DefaultPiPipeconf implements PiPipeconf {
41
42 private final PiPipeconfId id;
43 private final PiPipelineModel pipelineModel;
ghj0504520ec1a4202018-10-22 10:50:41 -070044 private final long fingerprint;
Carmelo Cascone07d72712017-07-14 15:57:47 -040045 private final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours;
Carmelo Cascone31d3e442017-07-18 16:58:51 -040046 private final Map<ExtensionType, URL> extensions;
Carmelo Cascone07d72712017-07-14 15:57:47 -040047
ghj0504520ec1a4202018-10-22 10:50:41 -070048 private DefaultPiPipeconf(PiPipeconfId id, PiPipelineModel pipelineModel, long fingerprint,
Carmelo Cascone07d72712017-07-14 15:57:47 -040049 Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours,
Carmelo Cascone31d3e442017-07-18 16:58:51 -040050 Map<ExtensionType, URL> extensions) {
Carmelo Cascone07d72712017-07-14 15:57:47 -040051 this.id = id;
52 this.pipelineModel = pipelineModel;
ghj0504520ec1a4202018-10-22 10:50:41 -070053 this.fingerprint = fingerprint;
Carmelo Cascone07d72712017-07-14 15:57:47 -040054 this.behaviours = behaviours;
55 this.extensions = extensions;
56 }
57
58 @Override
59 public PiPipeconfId id() {
60 return id;
61 }
62
63 @Override
64 public PiPipelineModel pipelineModel() {
65 return pipelineModel;
66 }
67
68 @Override
ghj0504520ec1a4202018-10-22 10:50:41 -070069 public long fingerprint() {
70 return fingerprint;
71 }
72
73 @Override
Carmelo Cascone07d72712017-07-14 15:57:47 -040074 public Collection<Class<? extends Behaviour>> behaviours() {
75 return behaviours.keySet();
76 }
77
78 @Override
79 public Optional<Class<? extends Behaviour>> implementation(Class<? extends Behaviour> behaviour) {
80 return Optional.ofNullable(behaviours.get(behaviour));
81 }
82
83 @Override
84 public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
85 return behaviours.containsKey(behaviourClass);
86 }
87
88 @Override
89 public Optional<InputStream> extension(ExtensionType type) {
Carmelo Cascone31d3e442017-07-18 16:58:51 -040090 if (extensions.containsKey(type)) {
91 try {
92 return Optional.of(extensions.get(type).openStream());
93 } catch (IOException e) {
Ray Milkey986a47a2018-01-25 11:38:51 -080094 throw new IllegalStateException(e);
Carmelo Cascone31d3e442017-07-18 16:58:51 -040095 }
96 } else {
97 return Optional.empty();
98 }
Carmelo Cascone07d72712017-07-14 15:57:47 -040099 }
100
101 /**
102 * Returns a new pipeconf builder.
103 *
104 * @return pipeconf builder
105 */
106 public static Builder builder() {
107 return new Builder();
108 }
109
110 /**
111 * Builder of pipeconf implementations.
112 */
113 public static class Builder {
114
115 private PiPipeconfId id;
116 private PiPipelineModel pipelineModel;
117 private ImmutableMap.Builder<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviourMapBuilder
118 = ImmutableMap.builder();
Carmelo Cascone31d3e442017-07-18 16:58:51 -0400119 private ImmutableMap.Builder<ExtensionType, URL> extensionMapBuilder = ImmutableMap.builder();
Carmelo Cascone07d72712017-07-14 15:57:47 -0400120
121 /**
122 * Sets the identifier of this pipeconf.
123 *
124 * @param id pipeconf identifier
125 * @return this
126 */
127 public Builder withId(PiPipeconfId id) {
128 this.id = id;
129 return this;
130 }
131
132 /**
133 * Sets the pipeline model of this pipeconf.
134 *
135 * @param model pipeline model
136 * @return this
137 */
138 public Builder withPipelineModel(PiPipelineModel model) {
139 this.pipelineModel = model;
140 return this;
141 }
142
143 /**
144 * Adds a behaviour to this pipeconf.
145 *
146 * @param clazz behavior interface class
147 * @param implementation behavior implementation class
148 * @return this
149 */
150 public Builder addBehaviour(Class<? extends Behaviour> clazz, Class<? extends Behaviour> implementation) {
151 checkNotNull(clazz);
152 checkNotNull(implementation);
153 behaviourMapBuilder.put(clazz, implementation);
154 return this;
155 }
156
157 /**
158 * Adds an extension to this pipeconf.
159 *
Carmelo Cascone31d3e442017-07-18 16:58:51 -0400160 * @param type extension type
161 * @param url url pointing at the extension file
Carmelo Cascone07d72712017-07-14 15:57:47 -0400162 * @return this
163 */
Carmelo Cascone31d3e442017-07-18 16:58:51 -0400164 public Builder addExtension(ExtensionType type, URL url) {
Carmelo Cascone07d72712017-07-14 15:57:47 -0400165 checkNotNull(type);
Carmelo Cascone31d3e442017-07-18 16:58:51 -0400166 checkNotNull(url);
167 checkArgument(checkUrl(url), format("Extension url %s seems to be empty/non existent", url.toString()));
168 extensionMapBuilder.put(type, url);
Carmelo Cascone07d72712017-07-14 15:57:47 -0400169 return this;
170 }
171
Carmelo Cascone31d3e442017-07-18 16:58:51 -0400172 private boolean checkUrl(URL url) {
173 try {
174 int byteCount = url.openStream().available();
175 return byteCount > 0;
176 } catch (IOException e) {
177 return false;
178 }
179 }
180
Carmelo Cascone07d72712017-07-14 15:57:47 -0400181 /**
182 * Creates a new pipeconf.
183 *
184 * @return pipeconf instance
185 */
186 public PiPipeconf build() {
187 checkNotNull(id);
188 checkNotNull(pipelineModel);
ghj0504520ec1a4202018-10-22 10:50:41 -0700189
190 Map<ExtensionType, URL> extensions = extensionMapBuilder.build();
191 return new DefaultPiPipeconf(id, pipelineModel, generateFingerprint(extensions),
192 behaviourMapBuilder.build(), extensions);
Carmelo Cascone07d72712017-07-14 15:57:47 -0400193 }
194
ghj0504520ec1a4202018-10-22 10:50:41 -0700195 private long generateFingerprint(Map<ExtensionType, URL> extensions) {
196 Collection<Integer> hashArray = new ArrayList<>();
197 for (Map.Entry<ExtensionType, URL> pair : extensions.entrySet()) {
198 try {
199 hashArray.add(Arrays.hashCode(ByteBuffer.wrap(IOUtils.toByteArray(
200 pair.getValue().openStream())).array()));
201 } catch (IOException e) {
202 throw new IllegalArgumentException(e);
203 }
204 }
205 return Arrays.hashCode(hashArray.toArray());
206 }
Carmelo Cascone07d72712017-07-14 15:57:47 -0400207 }
208}