Intent F/W improvements
- aggregate installables into FlowRuleOperations - added some impl. to SimpleIntentStore - created Coordinating State Change-Id: I5b26ec1fdb7aaff9d5da4f21b2d5a249568ac5ac
Showing
6 changed files
with
164 additions
and
90 deletions
| ... | @@ -15,16 +15,14 @@ | ... | @@ -15,16 +15,14 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.net.intent; | 16 | package org.onosproject.net.intent; |
| 17 | 17 | ||
| 18 | -import org.onosproject.net.flow.FlowRule; | ||
| 19 | -import org.onosproject.net.flow.FlowRuleBatchEntry; | ||
| 20 | import org.onosproject.net.flow.FlowRuleBatchOperation; | 18 | import org.onosproject.net.flow.FlowRuleBatchOperation; |
| 21 | -import org.onosproject.net.flow.FlowRuleOperations; | ||
| 22 | 19 | ||
| 23 | import java.util.List; | 20 | import java.util.List; |
| 24 | 21 | ||
| 25 | /** | 22 | /** |
| 26 | * Abstraction of entity capable of installing intents to the environment. | 23 | * Abstraction of entity capable of installing intents to the environment. |
| 27 | */ | 24 | */ |
| 25 | +//TODO consider refactoring this API | ||
| 28 | public interface IntentInstaller<T extends Intent> { | 26 | public interface IntentInstaller<T extends Intent> { |
| 29 | /** | 27 | /** |
| 30 | * Installs the specified intent to the environment. | 28 | * Installs the specified intent to the environment. |
| ... | @@ -33,32 +31,7 @@ public interface IntentInstaller<T extends Intent> { | ... | @@ -33,32 +31,7 @@ public interface IntentInstaller<T extends Intent> { |
| 33 | * @return flow rule operations to complete install | 31 | * @return flow rule operations to complete install |
| 34 | * @throws IntentException if issues are encountered while installing the intent | 32 | * @throws IntentException if issues are encountered while installing the intent |
| 35 | */ | 33 | */ |
| 36 | - @Deprecated | ||
| 37 | List<FlowRuleBatchOperation> install(T intent); | 34 | List<FlowRuleBatchOperation> install(T intent); |
| 38 | - // FIXME | ||
| 39 | - default FlowRuleOperations.Builder install2(T intent) { | ||
| 40 | - FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); | ||
| 41 | - for (FlowRuleBatchOperation batch : install(intent)) { | ||
| 42 | - for (FlowRuleBatchEntry entry : batch.getOperations()) { | ||
| 43 | - FlowRule rule = entry.target(); | ||
| 44 | - switch (entry.operator()) { | ||
| 45 | - case ADD: | ||
| 46 | - builder.add(rule); | ||
| 47 | - break; | ||
| 48 | - case REMOVE: | ||
| 49 | - builder.remove(rule); | ||
| 50 | - break; | ||
| 51 | - case MODIFY: | ||
| 52 | - builder.modify(rule); | ||
| 53 | - break; | ||
| 54 | - default: | ||
| 55 | - break; | ||
| 56 | - } | ||
| 57 | - } | ||
| 58 | - builder.newStage(); | ||
| 59 | - } | ||
| 60 | - return builder; | ||
| 61 | - } | ||
| 62 | 35 | ||
| 63 | /** | 36 | /** |
| 64 | * Uninstalls the specified intent from the environment. | 37 | * Uninstalls the specified intent from the environment. |
| ... | @@ -67,32 +40,7 @@ public interface IntentInstaller<T extends Intent> { | ... | @@ -67,32 +40,7 @@ public interface IntentInstaller<T extends Intent> { |
| 67 | * @return flow rule operations to complete uninstall | 40 | * @return flow rule operations to complete uninstall |
| 68 | * @throws IntentException if issues are encountered while uninstalling the intent | 41 | * @throws IntentException if issues are encountered while uninstalling the intent |
| 69 | */ | 42 | */ |
| 70 | - @Deprecated | ||
| 71 | List<FlowRuleBatchOperation> uninstall(T intent); | 43 | List<FlowRuleBatchOperation> uninstall(T intent); |
| 72 | - // FIXME | ||
| 73 | - default FlowRuleOperations.Builder uninstall2(T intent) { | ||
| 74 | - FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); | ||
| 75 | - for (FlowRuleBatchOperation batch : uninstall(intent)) { | ||
| 76 | - for (FlowRuleBatchEntry entry : batch.getOperations()) { | ||
| 77 | - FlowRule rule = entry.target(); | ||
| 78 | - switch (entry.operator()) { | ||
| 79 | - case ADD: | ||
| 80 | - builder.add(rule); | ||
| 81 | - break; | ||
| 82 | - case REMOVE: | ||
| 83 | - builder.remove(rule); | ||
| 84 | - break; | ||
| 85 | - case MODIFY: | ||
| 86 | - builder.modify(rule); | ||
| 87 | - break; | ||
| 88 | - default: | ||
| 89 | - break; | ||
| 90 | - } | ||
| 91 | - } | ||
| 92 | - builder.newStage(); | ||
| 93 | - } | ||
| 94 | - return builder; | ||
| 95 | - } | ||
| 96 | 44 | ||
| 97 | /** | 45 | /** |
| 98 | * Replaces the specified intent with a new one in the environment. | 46 | * Replaces the specified intent with a new one in the environment. |
| ... | @@ -104,29 +52,5 @@ public interface IntentInstaller<T extends Intent> { | ... | @@ -104,29 +52,5 @@ public interface IntentInstaller<T extends Intent> { |
| 104 | */ | 52 | */ |
| 105 | @Deprecated | 53 | @Deprecated |
| 106 | List<FlowRuleBatchOperation> replace(T oldIntent, T newIntent); | 54 | List<FlowRuleBatchOperation> replace(T oldIntent, T newIntent); |
| 107 | - // FIXME | ||
| 108 | - default FlowRuleOperations.Builder replace2(T oldIntent, T newIntent) { | ||
| 109 | - FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); | ||
| 110 | - for (FlowRuleBatchOperation batch : replace(oldIntent, newIntent)) { | ||
| 111 | - for (FlowRuleBatchEntry entry : batch.getOperations()) { | ||
| 112 | - FlowRule rule = entry.target(); | ||
| 113 | - switch (entry.operator()) { | ||
| 114 | - case ADD: | ||
| 115 | - builder.add(rule); | ||
| 116 | - break; | ||
| 117 | - case REMOVE: | ||
| 118 | - builder.remove(rule); | ||
| 119 | - break; | ||
| 120 | - case MODIFY: | ||
| 121 | - builder.modify(rule); | ||
| 122 | - break; | ||
| 123 | - default: | ||
| 124 | - break; | ||
| 125 | - } | ||
| 126 | - } | ||
| 127 | - builder.newStage(); | ||
| 128 | - } | ||
| 129 | - return builder; | ||
| 130 | - } | ||
| 131 | 55 | ||
| 132 | } | 56 | } | ... | ... |
| ... | @@ -46,7 +46,7 @@ class Compiling implements IntentUpdate { | ... | @@ -46,7 +46,7 @@ class Compiling implements IntentUpdate { |
| 46 | try { | 46 | try { |
| 47 | List<Intent> installables = (current != null) ? current.installables() : null; | 47 | List<Intent> installables = (current != null) ? current.installables() : null; |
| 48 | pending.setInstallables(intentManager.compileIntent(pending.intent(), installables)); | 48 | pending.setInstallables(intentManager.compileIntent(pending.intent(), installables)); |
| 49 | - return Optional.of(new Installing(intentManager, pending, current)); | 49 | + return Optional.of(new Coordinating(intentManager, pending, current)); |
| 50 | } catch (PathNotFoundException e) { | 50 | } catch (PathNotFoundException e) { |
| 51 | log.debug("Path not found for intent {}", pending.intent()); | 51 | log.debug("Path not found for intent {}", pending.intent()); |
| 52 | // TODO: revisit to implement failure handling | 52 | // TODO: revisit to implement failure handling | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015 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 | + */ | ||
| 16 | +package org.onosproject.net.intent.impl; | ||
| 17 | + | ||
| 18 | +import org.onosproject.net.flow.FlowRuleOperations; | ||
| 19 | +import org.onosproject.net.intent.IntentData; | ||
| 20 | +import org.slf4j.Logger; | ||
| 21 | +import org.slf4j.LoggerFactory; | ||
| 22 | + | ||
| 23 | +import java.util.Optional; | ||
| 24 | + | ||
| 25 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 26 | + | ||
| 27 | +// TODO: better naming because install() method actually generate FlowRuleBatchOperations | ||
| 28 | +class Coordinating implements IntentUpdate { | ||
| 29 | + | ||
| 30 | + private static final Logger log = LoggerFactory.getLogger(Coordinating.class); | ||
| 31 | + | ||
| 32 | + private final IntentManager intentManager; | ||
| 33 | + private final IntentData pending; | ||
| 34 | + private final IntentData current; | ||
| 35 | + | ||
| 36 | + // TODO: define an interface and use it, instead of IntentManager | ||
| 37 | + Coordinating(IntentManager intentManager, IntentData pending, IntentData current) { | ||
| 38 | + this.intentManager = checkNotNull(intentManager); | ||
| 39 | + this.pending = checkNotNull(pending); | ||
| 40 | + this.current = current; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + @Override | ||
| 44 | + public Optional<IntentUpdate> execute() { | ||
| 45 | + try { | ||
| 46 | + FlowRuleOperations flowRules = intentManager.coordinate(pending); | ||
| 47 | + return Optional.of(new Installing(intentManager, pending, flowRules)); | ||
| 48 | + } catch (FlowRuleBatchOperationConversionException e) { | ||
| 49 | + log.warn("Unable to install intent {} due to:", pending.intent().id(), e.getCause()); | ||
| 50 | + return Optional.of(new InstallingFailed(pending)); //FIXME | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | +} |
| ... | @@ -31,22 +31,19 @@ class Installing implements IntentUpdate { | ... | @@ -31,22 +31,19 @@ class Installing implements IntentUpdate { |
| 31 | 31 | ||
| 32 | private final IntentManager intentManager; | 32 | private final IntentManager intentManager; |
| 33 | private final IntentData pending; | 33 | private final IntentData pending; |
| 34 | - private final IntentData current; | 34 | + private final FlowRuleOperations flowRules; |
| 35 | 35 | ||
| 36 | // TODO: define an interface and use it, instead of IntentManager | 36 | // TODO: define an interface and use it, instead of IntentManager |
| 37 | - Installing(IntentManager intentManager, IntentData pending, IntentData current) { | 37 | + Installing(IntentManager intentManager, IntentData pending, FlowRuleOperations flowRules) { |
| 38 | this.intentManager = checkNotNull(intentManager); | 38 | this.intentManager = checkNotNull(intentManager); |
| 39 | this.pending = checkNotNull(pending); | 39 | this.pending = checkNotNull(pending); |
| 40 | - this.current = current; | 40 | + this.flowRules = flowRules; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | @Override | 43 | @Override |
| 44 | public Optional<IntentUpdate> execute() { | 44 | public Optional<IntentUpdate> execute() { |
| 45 | try { | 45 | try { |
| 46 | - FlowRuleOperations flowRules = intentManager.coordinate(pending.installables()); | 46 | + intentManager.flowRuleService.apply(flowRules); // FIXME we need to provide a context |
| 47 | - // TODO: call FlowRuleService API to push FlowRules and track resources, | ||
| 48 | - // which the submitted intent will use. | ||
| 49 | - intentManager.flowRuleService.apply(flowRules); | ||
| 50 | return Optional.of(new Installed(pending)); | 47 | return Optional.of(new Installed(pending)); |
| 51 | } catch (FlowRuleBatchOperationConversionException e) { | 48 | } catch (FlowRuleBatchOperationConversionException e) { |
| 52 | log.warn("Unable to install intent {} due to:", pending.intent().id(), e.getCause()); | 49 | log.warn("Unable to install intent {} due to:", pending.intent().id(), e.getCause()); | ... | ... |
| ... | @@ -28,8 +28,13 @@ import org.onosproject.core.CoreService; | ... | @@ -28,8 +28,13 @@ import org.onosproject.core.CoreService; |
| 28 | import org.onosproject.core.IdGenerator; | 28 | import org.onosproject.core.IdGenerator; |
| 29 | import org.onosproject.event.AbstractListenerRegistry; | 29 | import org.onosproject.event.AbstractListenerRegistry; |
| 30 | import org.onosproject.event.EventDeliveryService; | 30 | import org.onosproject.event.EventDeliveryService; |
| 31 | +import org.onosproject.net.flow.FlowRule; | ||
| 32 | +import org.onosproject.net.flow.FlowRuleBatchEntry; | ||
| 31 | import org.onosproject.net.flow.FlowRuleBatchOperation; | 33 | import org.onosproject.net.flow.FlowRuleBatchOperation; |
| 34 | +import org.onosproject.net.flow.FlowRuleEvent; | ||
| 35 | +import org.onosproject.net.flow.FlowRuleListener; | ||
| 32 | import org.onosproject.net.flow.FlowRuleOperations; | 36 | import org.onosproject.net.flow.FlowRuleOperations; |
| 37 | +import org.onosproject.net.flow.FlowRuleOperationsContext; | ||
| 33 | import org.onosproject.net.flow.FlowRuleService; | 38 | import org.onosproject.net.flow.FlowRuleService; |
| 34 | import org.onosproject.net.intent.Intent; | 39 | import org.onosproject.net.intent.Intent; |
| 35 | import org.onosproject.net.intent.IntentBatchDelegate; | 40 | import org.onosproject.net.intent.IntentBatchDelegate; |
| ... | @@ -50,6 +55,7 @@ import org.slf4j.Logger; | ... | @@ -50,6 +55,7 @@ import org.slf4j.Logger; |
| 50 | import java.util.ArrayList; | 55 | import java.util.ArrayList; |
| 51 | import java.util.Collection; | 56 | import java.util.Collection; |
| 52 | import java.util.EnumSet; | 57 | import java.util.EnumSet; |
| 58 | +import java.util.Iterator; | ||
| 53 | import java.util.List; | 59 | import java.util.List; |
| 54 | import java.util.Map; | 60 | import java.util.Map; |
| 55 | import java.util.Optional; | 61 | import java.util.Optional; |
| ... | @@ -281,19 +287,74 @@ public class IntentManager | ... | @@ -281,19 +287,74 @@ public class IntentManager |
| 281 | 287 | ||
| 282 | //TODO javadoc | 288 | //TODO javadoc |
| 283 | //FIXME | 289 | //FIXME |
| 284 | - FlowRuleOperations coordinate(List<Intent> installables) { | 290 | + FlowRuleOperations coordinate(IntentData pending) { |
| 285 | - //List<FlowRuleBatchOperation> batches = new ArrayList<>(installables.size()); | 291 | + List<Intent> installables = pending.installables(); |
| 292 | + List<List<FlowRuleBatchOperation>> plans = new ArrayList<>(installables.size()); | ||
| 286 | for (Intent installable : installables) { | 293 | for (Intent installable : installables) { |
| 287 | try { | 294 | try { |
| 288 | registerSubclassInstallerIfNeeded(installable); | 295 | registerSubclassInstallerIfNeeded(installable); |
| 289 | //FIXME need to migrate installers to FlowRuleOperations | 296 | //FIXME need to migrate installers to FlowRuleOperations |
| 290 | // FIXME need to aggregate the FlowRuleOperations across installables | 297 | // FIXME need to aggregate the FlowRuleOperations across installables |
| 291 | - getInstaller(installable).install2(installable).build(null/*FIXME*/); | 298 | + plans.add(getInstaller(installable).install(installable)); |
| 292 | } catch (Exception e) { // TODO this should be IntentException | 299 | } catch (Exception e) { // TODO this should be IntentException |
| 293 | throw new FlowRuleBatchOperationConversionException(null/*FIXME*/, e); | 300 | throw new FlowRuleBatchOperationConversionException(null/*FIXME*/, e); |
| 294 | } | 301 | } |
| 295 | } | 302 | } |
| 296 | - return null; | 303 | + |
| 304 | + return merge(plans).build(new FlowRuleOperationsContext() { // FIXME move this out | ||
| 305 | + @Override | ||
| 306 | + public void onSuccess(FlowRuleOperations ops) { | ||
| 307 | + log.info("Completed installing: {}", pending.key()); | ||
| 308 | + pending.setState(INSTALLED); | ||
| 309 | + store.write(pending); | ||
| 310 | + } | ||
| 311 | + | ||
| 312 | + @Override | ||
| 313 | + public void onError(FlowRuleOperations ops) { | ||
| 314 | + //FIXME store.write(pending.setState(BROKEN)); | ||
| 315 | + } | ||
| 316 | + }); | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + // FIXME... needs tests... or maybe it's just perfect | ||
| 320 | + private FlowRuleOperations.Builder merge(List<List<FlowRuleBatchOperation>> plans) { | ||
| 321 | + FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); | ||
| 322 | + // Build a batch one stage at a time | ||
| 323 | + for (int stageNumber = 0;; stageNumber++) { | ||
| 324 | + // Get the sub-stage from each plan (List<FlowRuleBatchOperation>) | ||
| 325 | + for (Iterator<List<FlowRuleBatchOperation>> itr = plans.iterator(); itr.hasNext();) { | ||
| 326 | + List<FlowRuleBatchOperation> plan = itr.next(); | ||
| 327 | + if (plan.size() <= stageNumber) { | ||
| 328 | + // we have consumed all stages from this plan, so remove it | ||
| 329 | + itr.remove(); | ||
| 330 | + continue; | ||
| 331 | + } | ||
| 332 | + // write operations from this sub-stage into the builder | ||
| 333 | + FlowRuleBatchOperation stage = plan.get(stageNumber); | ||
| 334 | + for (FlowRuleBatchEntry entry : stage.getOperations()) { | ||
| 335 | + FlowRule rule = entry.target(); | ||
| 336 | + switch (entry.operator()) { | ||
| 337 | + case ADD: | ||
| 338 | + builder.add(rule); | ||
| 339 | + break; | ||
| 340 | + case REMOVE: | ||
| 341 | + builder.remove(rule); | ||
| 342 | + break; | ||
| 343 | + case MODIFY: | ||
| 344 | + builder.modify(rule); | ||
| 345 | + break; | ||
| 346 | + default: | ||
| 347 | + break; | ||
| 348 | + } | ||
| 349 | + } | ||
| 350 | + } | ||
| 351 | + // we are done with the stage, start the next one... | ||
| 352 | + if (plans.isEmpty()) { | ||
| 353 | + break; // we don't need to start a new stage, we are done. | ||
| 354 | + } | ||
| 355 | + builder.newStage(); | ||
| 356 | + } | ||
| 357 | + return builder; | ||
| 297 | } | 358 | } |
| 298 | 359 | ||
| 299 | /** | 360 | /** |
| ... | @@ -311,7 +372,7 @@ public class IntentManager | ... | @@ -311,7 +372,7 @@ public class IntentManager |
| 311 | installable.resources()); | 372 | installable.resources()); |
| 312 | try { | 373 | try { |
| 313 | // FIXME need to aggregate the FlowRuleOperations across installables | 374 | // FIXME need to aggregate the FlowRuleOperations across installables |
| 314 | - getInstaller(installable).uninstall2(installable).build(null/*FIXME*/); | 375 | + getInstaller(installable).uninstall(installable); //.build(null/*FIXME*/); |
| 315 | } catch (IntentException e) { | 376 | } catch (IntentException e) { |
| 316 | log.warn("Unable to uninstall intent {} due to:", intent.id(), e); | 377 | log.warn("Unable to uninstall intent {} due to:", intent.id(), e); |
| 317 | // TODO: this should never happen. but what if it does? | 378 | // TODO: this should never happen. but what if it does? | ... | ... |
| ... | @@ -25,6 +25,8 @@ import org.onosproject.net.intent.BatchWrite.Operation; | ... | @@ -25,6 +25,8 @@ import org.onosproject.net.intent.BatchWrite.Operation; |
| 25 | import org.onosproject.net.intent.Intent; | 25 | import org.onosproject.net.intent.Intent; |
| 26 | import org.onosproject.net.intent.IntentData; | 26 | import org.onosproject.net.intent.IntentData; |
| 27 | import org.onosproject.net.intent.IntentEvent; | 27 | import org.onosproject.net.intent.IntentEvent; |
| 28 | +import org.onosproject.net.intent.IntentId; | ||
| 29 | +import org.onosproject.net.intent.IntentState; | ||
| 28 | import org.onosproject.net.intent.IntentStore; | 30 | import org.onosproject.net.intent.IntentStore; |
| 29 | import org.onosproject.net.intent.IntentStoreDelegate; | 31 | import org.onosproject.net.intent.IntentStoreDelegate; |
| 30 | import org.onosproject.net.intent.Key; | 32 | import org.onosproject.net.intent.Key; |
| ... | @@ -33,6 +35,7 @@ import org.slf4j.Logger; | ... | @@ -33,6 +35,7 @@ import org.slf4j.Logger; |
| 33 | 35 | ||
| 34 | import java.util.List; | 36 | import java.util.List; |
| 35 | import java.util.Map; | 37 | import java.util.Map; |
| 38 | +import java.util.Objects; | ||
| 36 | import java.util.stream.Collectors; | 39 | import java.util.stream.Collectors; |
| 37 | 40 | ||
| 38 | import static com.google.common.base.Preconditions.checkNotNull; | 41 | import static com.google.common.base.Preconditions.checkNotNull; |
| ... | @@ -73,6 +76,36 @@ public class SimpleIntentStore | ... | @@ -73,6 +76,36 @@ public class SimpleIntentStore |
| 73 | } | 76 | } |
| 74 | 77 | ||
| 75 | @Override | 78 | @Override |
| 79 | + public Intent getIntent(IntentId intentId) { | ||
| 80 | + for (IntentData data : current.values()) { | ||
| 81 | + if (Objects.equals(data.intent().id(), intentId)) { | ||
| 82 | + return data.intent(); | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + return null; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + @Override | ||
| 89 | + public IntentState getIntentState(IntentId intentId) { | ||
| 90 | + for (IntentData data : current.values()) { | ||
| 91 | + if (Objects.equals(data.intent().id(), intentId)) { | ||
| 92 | + return data.state(); | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + return null; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + @Override | ||
| 99 | + public List<Intent> getInstallableIntents(IntentId intentId) { | ||
| 100 | + for (IntentData data : current.values()) { | ||
| 101 | + if (Objects.equals(data.intent().id(), intentId)) { | ||
| 102 | + return data.installables(); | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + return null; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + @Override | ||
| 76 | public IntentData getIntentData(Key key) { | 109 | public IntentData getIntentData(Key key) { |
| 77 | return current.get(key); | 110 | return current.get(key); |
| 78 | } | 111 | } |
| ... | @@ -164,6 +197,12 @@ public class SimpleIntentStore | ... | @@ -164,6 +197,12 @@ public class SimpleIntentStore |
| 164 | } | 197 | } |
| 165 | } | 198 | } |
| 166 | 199 | ||
| 200 | + @Override | ||
| 201 | + public Intent getIntent(Key key) { | ||
| 202 | + IntentData data = current.get(key); | ||
| 203 | + return (data != null) ? data.intent() : null; | ||
| 204 | + } | ||
| 205 | + | ||
| 167 | 206 | ||
| 168 | @Override | 207 | @Override |
| 169 | public void addPending(IntentData data) { | 208 | public void addPending(IntentData data) { | ... | ... |
-
Please register or login to post a comment