| 
001 /*002  * Copyright 2008-2015 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 }
 |