| 
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 griffon.core.CallableWithArgs;
 019 import groovy.lang.Closure;
 020 import groovy.util.FactoryBuilderSupport;
 021
 022 import javax.annotation.Nonnull;
 023 import javax.annotation.Nullable;
 024 import java.util.LinkedHashMap;
 025 import java.util.Map;
 026
 027 import static griffon.util.GriffonNameUtils.isBlank;
 028 import static java.util.Objects.requireNonNull;
 029
 030 /**
 031  * Helper class for constructing bindings between two objects.
 032  *
 033  * @author Andres Almiray
 034  * @since 2.0.0
 035  */
 036 public class BindUtils {
 037     /**
 038      * Create a new Binding using a builder.
 039      */
 040     @Nonnull
 041     public static BindingBuilder binding() {
 042         return new BindingBuilder();
 043     }
 044
 045     public static class BindingBuilder {
 046         private Object source;
 047         private Object target;
 048         private String sourceProperty;
 049         private String targetProperty;
 050         private CallableWithArgs<?> converter;
 051         private CallableWithArgs<?> validator;
 052         private boolean mutual;
 053
 054         @Nonnull
 055         public BindingBuilder withSource(@Nullable Object source) {
 056             this.source = source;
 057             return this;
 058         }
 059
 060         @Nonnull
 061         public BindingBuilder withTarget(@Nullable Object target) {
 062             this.target = target;
 063             return this;
 064         }
 065
 066         @Nonnull
 067         public BindingBuilder withSourceProperty(@Nullable String sourceProperty) {
 068             this.sourceProperty = sourceProperty;
 069             return this;
 070         }
 071
 072         @Nonnull
 073         public BindingBuilder withTargetProperty(@Nullable String targetProperty) {
 074             this.targetProperty = targetProperty;
 075             return this;
 076         }
 077
 078         @Nonnull
 079         public BindingBuilder withConverter(@Nullable CallableWithArgs<?> converter) {
 080             this.converter = converter;
 081             return this;
 082         }
 083
 084         @Nonnull
 085         public BindingBuilder withValidator(@Nullable CallableWithArgs<?> validator) {
 086             this.validator = validator;
 087             return this;
 088         }
 089
 090         @Nonnull
 091         public BindingBuilder withMutual(boolean mutual) {
 092             this.mutual = mutual;
 093             return this;
 094         }
 095
 096         public void make(@Nonnull FactoryBuilderSupport builder) {
 097             requireNonNull(builder, "Cannot make binding with a null builder!");
 098             requireNonNull(source, "Unspecified value for: source");
 099             requireNonNull(target, "Unspecified value for: target");
 100
 101             Map<String, Object> attributes = new LinkedHashMap<>();
 102
 103             if (isBlank(sourceProperty)) sourceProperty = targetProperty;
 104             if (isBlank(sourceProperty)) {
 105                 throw new IllegalArgumentException("Unspecified values for: sourceProperty, targetProperty");
 106             }
 107             if (isBlank(targetProperty)) targetProperty = sourceProperty;
 108
 109             attributes.put("source", source);
 110             attributes.put("target", target);
 111             attributes.put("sourceProperty", sourceProperty);
 112             attributes.put("targetProperty", targetProperty);
 113             attributes.put("mutual", mutual);
 114
 115             if (converter != null) {
 116                 attributes.put("converter", makeClosure(builder, converter));
 117             }
 118             if (validator != null) {
 119                 attributes.put("validator", makeClosure(builder, validator));
 120             }
 121
 122             builder.invokeMethod("bind", attributes);
 123         }
 124
 125         private Closure<?> makeClosure(@Nonnull FactoryBuilderSupport builder, @Nonnull final CallableWithArgs<?> callback) {
 126             if (callback instanceof Closure) {
 127                 return (Closure<?>) callback;
 128             }
 129             return new Closure<Object>(builder) {
 130                 private static final long serialVersionUID = -4108869890482462552L;
 131
 132                 @Override
 133                 public Object call(Object... args) {
 134                     return callback.call(args);
 135                 }
 136
 137                 @Override
 138                 public Object call(Object args) {
 139                     return callback.call(args);
 140                     // return callback.call(arguments != null && arguments.getClass().isArray() ? (Object[]) arguments : new Object[]{arguments});
 141                 }
 142             };
 143         }
 144     }
 145 }
 |