blob: 29d5a5fecb9925719257a30131ffb7a5e900b8be [file] [log] [blame]
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -08003 *
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.intent.impl;
17
18import com.google.common.collect.ImmutableList;
19import com.google.common.collect.ImmutableMap;
Ayaka Koshibebcb02372015-06-01 10:56:42 -070020
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -080021import org.onosproject.net.intent.Intent;
22import org.onosproject.net.intent.IntentCompiler;
23import org.onosproject.net.intent.IntentException;
24
25import java.util.ArrayList;
Yuta HIGUCHI51590ff2017-01-27 18:39:12 -080026import java.util.LinkedList;
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -080027import java.util.List;
28import java.util.Map;
Yuta HIGUCHI51590ff2017-01-27 18:39:12 -080029import java.util.Queue;
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -080030import java.util.concurrent.ConcurrentHashMap;
31import java.util.concurrent.ConcurrentMap;
32
33// TODO: consider a better name
34class CompilerRegistry {
35
36 private final ConcurrentMap<Class<? extends Intent>,
37 IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
38
39 /**
40 * Registers the specified compiler for the given intent class.
41 *
42 * @param cls intent class
43 * @param compiler intent compiler
44 * @param <T> the type of intent
45 */
46 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
47 compilers.put(cls, compiler);
48 }
49
50 /**
51 * Unregisters the compiler for the specified intent class.
52 *
53 * @param cls intent class
54 * @param <T> the type of intent
55 */
56 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
57 compilers.remove(cls);
58 }
59
60 /**
61 * Returns immutable set of bindings of currently registered intent compilers.
62 *
63 * @return the set of compiler bindings
64 */
65 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
66 return ImmutableMap.copyOf(compilers);
67 }
68
69 /**
70 * Compiles an intent recursively.
71 *
72 * @param intent intent
73 * @param previousInstallables previous intent installables
74 * @return result of compilation
75 */
76 List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
77 if (intent.isInstallable()) {
78 return ImmutableList.of(intent);
79 }
80
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -080081 // FIXME: get previous resources
Yuta HIGUCHI51590ff2017-01-27 18:39:12 -080082 List<Intent> installables = new ArrayList<>();
83 Queue<Intent> compileQueue = new LinkedList<>();
84 compileQueue.add(intent);
85
86 Intent compiling;
87 while ((compiling = compileQueue.poll()) != null) {
88 registerSubclassCompilerIfNeeded(compiling);
89
90 List<Intent> compiled = getCompiler(compiling)
91 .compile(compiling, previousInstallables);
92
93 compiled.forEach(i -> {
94 if (i.isInstallable()) {
95 installables.add(i);
96 } else {
97 compileQueue.add(i);
98 }
99 });
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800100 }
Yuta HIGUCHI51590ff2017-01-27 18:39:12 -0800101 return installables;
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800102 }
103
104 /**
105 * Returns the corresponding intent compiler to the specified intent.
106 *
107 * @param intent intent
108 * @param <T> the type of intent
109 * @return intent compiler corresponding to the specified intent
110 */
111 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
112 @SuppressWarnings("unchecked")
113 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
114 if (compiler == null) {
115 throw new IntentException("no compiler for class " + intent.getClass());
116 }
117 return compiler;
118 }
119
120 /**
121 * Registers an intent compiler of the specified intent if an intent compiler
122 * for the intent is not registered. This method traverses the class hierarchy of
123 * the intent. Once an intent compiler for a parent type is found, this method
124 * registers the found intent compiler.
125 *
126 * @param intent intent
127 */
128 private void registerSubclassCompilerIfNeeded(Intent intent) {
129 if (!compilers.containsKey(intent.getClass())) {
130 Class<?> cls = intent.getClass();
131 while (cls != Object.class) {
132 // As long as we're within the Intent class descendants
133 if (Intent.class.isAssignableFrom(cls)) {
134 IntentCompiler<?> compiler = compilers.get(cls);
135 if (compiler != null) {
136 compilers.put(intent.getClass(), compiler);
137 return;
138 }
139 }
140 cls = cls.getSuperclass();
141 }
142 }
143 }
144}