001 /*
002 * Copyright 2008-2014 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package griffon.util;
017
018 import groovy.lang.Closure;
019 import groovy.lang.MissingMethodException;
020 import groovy.lang.MissingPropertyException;
021 import groovy.util.Factory;
022 import groovy.util.FactoryBuilderSupport;
023
024 import javax.annotation.Nonnull;
025 import java.util.ArrayList;
026 import java.util.List;
027 import java.util.Map;
028
029 import static java.util.Objects.requireNonNull;
030
031 /**
032 * @author Andres Almiray
033 * @since 2.0.0
034 */
035 @SuppressWarnings("rawtypes")
036 public class CompositeBuilder extends FactoryBuilderSupport {
037 public CompositeBuilder(@Nonnull BuilderCustomizer[] customizers) {
038 super(false);
039 requireNonNull(customizers, "Argument 'customizers' must not be null");
040 for (int i = 0; i < customizers.length; i++) {
041 BuilderCustomizer customizer = customizers[customizers.length - 1 - i];
042 doRegisterVariables(customizer);
043 doRegisterFactories(customizer);
044 doRegisterMethods(customizer);
045 doRegisterProps(customizer);
046 }
047
048 final List<Closure> methodMissingDelegates = new ArrayList<>();
049 final List<Closure> propertyMissingDelegates = new ArrayList<>();
050 for (BuilderCustomizer customizer : customizers) {
051 doRegisterAttributeDelegates(customizer);
052 doRegisterPreInstantiateDelegates(customizer);
053 doRegisterPostInstantiateDelegates(customizer);
054 doRegisterPostNodeCompletionDelegates(customizer);
055 doDisposalClosures(customizer);
056 if (customizer.getMethodMissingDelegate() != null) {
057 methodMissingDelegates.add(customizer.getMethodMissingDelegate());
058 }
059 if (customizer.getPropertyMissingDelegate() != null) {
060 propertyMissingDelegates.add(customizer.getPropertyMissingDelegate());
061 }
062 }
063
064 final Closure originalMethodMissingDelegate = getMethodMissingDelegate();
065 setMethodMissingDelegate(new Closure<Object>(this) {
066 private static final long serialVersionUID = -6901410680736336645L;
067
068 protected Object doCall(Object[] args) {
069 String methodName = String.valueOf(args[0]);
070 for (Closure methodMissingDelegate : methodMissingDelegates) {
071 try {
072 return methodMissingDelegate.call(args);
073 } catch (MissingMethodException mme) {
074 if (!methodName.equals(mme.getMethod())) throw mme;
075 }
076 }
077
078 if (originalMethodMissingDelegate != null) {
079 try {
080 return originalMethodMissingDelegate.call(args);
081 } catch (MissingMethodException mme) {
082 if (!methodName.equals(mme.getMethod())) throw mme;
083 }
084 }
085
086 Object[] argsCopy = new Object[args.length - 1];
087 System.arraycopy(args, 1, argsCopy, 0, argsCopy.length);
088 throw new MissingMethodException(methodName, CompositeBuilder.class, argsCopy);
089 }
090 });
091
092 final Closure originalPropertyMissingDelegate = getMethodMissingDelegate();
093 setPropertyMissingDelegate(new Closure<Object>(this) {
094 private static final long serialVersionUID = 1055591497264374109L;
095
096 protected Object doCall(Object[] args) {
097 String propertyName = String.valueOf(args[0]);
098 for (Closure propertyMissingDelegate : propertyMissingDelegates) {
099 try {
100 return propertyMissingDelegate.call(args);
101 } catch (MissingMethodException mme) {
102 if (!propertyName.equals(mme.getMethod()))
103 throw mme;
104 }
105 }
106
107 if (originalPropertyMissingDelegate != null) {
108 try {
109 return originalPropertyMissingDelegate.call(args);
110 } catch (MissingMethodException mme) {
111 if (!propertyName.equals(mme.getMethod()))
112 throw mme;
113 }
114 }
115
116 throw new MissingPropertyException(propertyName, CompositeBuilder.class);
117 }
118 });
119 }
120
121 private void doRegisterVariables(@Nonnull BuilderCustomizer customizer) {
122 for (Map.Entry<String, Object> entry : customizer.getVariables().entrySet()) {
123 setVariable(entry.getKey(), entry.getValue());
124 }
125 }
126
127 private void doRegisterFactories(@Nonnull BuilderCustomizer customizer) {
128 for (Map.Entry<String, Factory> entry : customizer.getFactories().entrySet()) {
129 registerFactory(entry.getKey(), entry.getValue());
130 }
131 }
132
133 private void doRegisterMethods(@Nonnull BuilderCustomizer customizer) {
134 for (Map.Entry<String, Closure> e : customizer.getMethods().entrySet()) {
135 registerExplicitMethod(e.getKey(), e.getValue());
136 }
137 }
138
139 private void doRegisterProps(@Nonnull BuilderCustomizer customizer) {
140 for (Map.Entry<String, Closure[]> entry : customizer.getProps().entrySet()) {
141 Closure[] accessors = entry.getValue();
142 Closure getter = accessors[0];
143 Closure setter = accessors[1];
144 registerExplicitProperty(entry.getKey(), getter, setter);
145 }
146 }
147
148 private void doRegisterAttributeDelegates(@Nonnull BuilderCustomizer customizer) {
149 for (Closure c : customizer.getAttributeDelegates()) {
150 addAttributeDelegate(c);
151 }
152 }
153
154 private void doRegisterPreInstantiateDelegates(@Nonnull BuilderCustomizer customizer) {
155 for (Closure c : customizer.getPreInstantiateDelegates()) {
156 addPreInstantiateDelegate(c);
157 }
158 }
159
160 private void doRegisterPostInstantiateDelegates(@Nonnull BuilderCustomizer customizer) {
161 for (Closure c : customizer.getPostInstantiateDelegates()) {
162 addPostInstantiateDelegate(c);
163 }
164 }
165
166 private void doRegisterPostNodeCompletionDelegates(@Nonnull BuilderCustomizer customizer) {
167 for (Closure c : customizer.getPostNodeCompletionDelegates()) {
168 addPostNodeCompletionDelegate(c);
169 }
170 }
171
172 private void doDisposalClosures(@Nonnull BuilderCustomizer customizer) {
173 for (Closure c : customizer.getDisposalClosures()) {
174 addDisposalClosure(c);
175 }
176 }
177 }
|