1 /*
2 * Grapht, an open source dependency injector.
3 * Copyright 2014-2015 various contributors (see CONTRIBUTORS.txt)
4 * Copyright 2010-2014 Regents of the University of Minnesota
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 51
18 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 package org.grouplens.grapht.solver;
21
22 import com.google.common.base.Predicate;
23 import org.grouplens.grapht.reflect.Desire;
24 import org.grouplens.grapht.util.AbstractChain;
25
26 import javax.annotation.Nonnull;
27 import javax.annotation.Nullable;
28 import java.util.Collections;
29 import java.util.List;
30 import java.util.UUID;
31
32 /**
33 * A sequence of desires. When one desire is resolved, that resolution can be a desire that needs
34 * further resolution. These desires are accumulated in a desire chain. Desire chains are
35 * immutable; appending to one results in a new desire chain object pointing to the previous chain.
36 * They form a reverse singly linked list. The chain maintains O(1) access to both the initial and
37 * current desires.
38 *
39 * <p>When iterating a desire chain the initial desire is first and the most recent desire is last.
40 *
41 * @since 0.7.0
42 * @author <a href="http://www.grouplens.org">GroupLens Research</a>
43 */
44 public class DesireChain extends AbstractChain<Desire> {
45 @Nonnull
46 private final Desire initialDesire;
47 private final UUID key;
48
49 public static DesireChain singleton(Desire desire) {
50 return new DesireChain(null, desire);
51 }
52
53 /**
54 * Create a new desire chain.
55 * @param prev The previous chain.
56 * @param d The desire.
57 */
58 private DesireChain(DesireChain prev, @Nonnull Desire d) {
59 super(prev, d);
60 key = prev == null ? UUID.randomUUID() : prev.key;
61 initialDesire = prev == null ? d : prev.getInitialDesire();
62 }
63
64 public static Predicate<DesireChain> hasInitialDesire(final Desire d) {
65 return new Predicate<DesireChain>() {
66 @Override
67 public boolean apply(@Nullable DesireChain input) {
68 return input != null && input.getInitialDesire().equals(d);
69 }
70 };
71 }
72
73 @Nonnull
74 public Desire getCurrentDesire() {
75 return tailValue;
76 }
77
78 @Nonnull
79 public Desire getInitialDesire() {
80 return initialDesire;
81 }
82
83 /**
84 * Return the list of desires up to, but not including, the current desire.
85 * @return The previous desire chain.
86 */
87 @Nonnull
88 public List<Desire> getPreviousDesires() {
89 if (previous == null) {
90 return Collections.emptyList();
91 } else {
92 return previous;
93 }
94 }
95
96 /**
97 * Return the desire chain up to, but not including, the current desire.
98 * @return The previous desire chain.
99 */
100 @Nonnull
101 public DesireChain getPreviousDesireChain() {
102 if (previous == null) {
103 throw new IllegalArgumentException("cannot get previous chain from singleton");
104 } else {
105 return (DesireChain) previous;
106 }
107 }
108
109 /**
110 * Get this chain's key. Each chain has a key, a unique object that is created when the chain
111 * is created (via {@link #singleton(org.grouplens.grapht.reflect.Desire)}), and preserved through
112 * {@link #extend(org.grouplens.grapht.reflect.Desire)} operations. It can be used to remember
113 * state across invocations of a binding function as a desire chain is built up.
114 * @return The chain's key.
115 */
116 public Object getKey() {
117 return key;
118 }
119
120 /**
121 * Extend this chain with a new desire. The chain is not modified; this method returns a new
122 * chain that includes the new desire as its current desire.
123 *
124 * @param d The new current desire.
125 * @return The new desire chain.
126 */
127 @Nonnull
128 public DesireChain extend(@Nonnull Desire d) {
129 return new DesireChain(this, d);
130 }
131 }