// Path: impl/src/main/java/com/guigarage/binding/SwingBinding.java
// public class SwingBinding {
// 
//     private static Executor backgroundExecutor = Executors.newSingleThreadExecutor();
// 
//     public static <T> ConvertableBidirectionalBindable<T> bind(final Component component, final String attribute) {
//         return new ConvertableBidirectionalBindable<T>() {
// 
//             private AtomicBoolean bindingCalled = new AtomicBoolean(false);
// 
//             private Consumer<Throwable> errorHandler = e -> e.printStackTrace();
// 
//             private Lock bindingLock = new ReentrantLock();
// 
//             private <U> U callLocked(Supplier<U> supplier) {
//                 bindingLock.lock();
//                 try {
//                     return supplier.get();
//                 } finally {
//                     bindingLock.unlock();
//                 }
//             }
// 
//             private void callLocked(Runnable runnable) {
//                 callLocked(() -> {
//                     runnable.run();
//                     return null;
//                 });
//             }
// 
//             @Override
//             public <U> Subscription bidirectionalTo(Property<U> property, Function<U, T> converter, Function<T, U> converter2) {
//                 try {
//                     final PropertyDescriptor propertyDescriptor = new PropertyDescriptor(attribute, component.getClass());
//                     final PropertyEditor propertyEditor = propertyDescriptor.createPropertyEditor(component);
//                     Subscription subscription = bind(property, converter, propertyEditor);
// 
//                     PropertyChangeListener listener = e -> {
//                         if (!bindingCalled.get()) {
//                             bindingCalled.set(true);
//                             try {
//                                 backgroundExecutor.execute(() -> {
//                                     callLocked(() -> {
//                                         try {
//                                             property.setValue(converter2.apply((T) e.getNewValue()));
//                                         } catch (Exception ex) {
//                                             SwingUtilities.invokeLater(() -> {
//                                                 errorHandler.accept(ex);
//                                             });
//                                         }
//                                     });
//                                 });
//                             } catch (Exception e1) {
//                                 errorHandler.accept(e1);
//                             } finally {
//                                 bindingCalled.set(false);
//                             }
//                         }
//                     };
// 
//                     component.addPropertyChangeListener(listener);
// 
//                     return () -> {
//                         component.removePropertyChangeListener(listener);
//                         subscription.unsubscribe();
//                     };
//                 } catch (Exception e1) {
//                     throw new RuntimeException("Can not bind!", e1);
//                 }
//             }
// 
//             @Override
//             public <U> Subscription to(Observable<U> observable, Function<U, T> converter) {
//                 try {
//                     final PropertyDescriptor propertyDescriptor = new PropertyDescriptor(attribute, component.getClass());
//                     final PropertyEditor propertyEditor = propertyDescriptor.createPropertyEditor(component);
//                     return bind(observable, converter, propertyEditor);
//                 } catch (Exception e1) {
//                     throw new RuntimeException("Can not bind!", e1);
//                 }
//             }
// 
//             private <U> Subscription bind(Observable<U> observable, Function<U, T> converter, PropertyEditor propertyEditor) {
//                 return observable.onChanged(e -> {
//                     callLocked(() -> {
//                         try {
//                             SwingUtilities.invokeAndWait(() -> {
//                                 if (!bindingCalled.get()) {
//                                     bindingCalled.set(true);
//                                     try {
//                                         propertyEditor.setValue(converter.apply(e.getValue()));
//                                     } catch (Exception e1) {
//                                         errorHandler.accept(e1);
//                                     } finally {
//                                         bindingCalled.set(false);
//                                     }
//                                 }
//                             });
//                         } catch (Exception e1) {
//                             SwingUtilities.invokeLater(() -> {
//                                 errorHandler.accept(e1);
//                             });
//                         }
//                     });
//                 });
//             }
// 
//             @Override
//             public ConvertableBindable<T> withErrorHandler(Consumer<Throwable> handler) {
//                 this.errorHandler = handler;
//                 return this;
//             }
// 
//         };
//     }
// }
// 
// Path: impl/src/main/java/com/guigarage/observer/BasicProperty.java
// public class BasicProperty<V> extends BasicObservable<V> implements Property<V> {
// 
//     @Override
//     public void setValue(V value) {
//         updateValue(value);
//     }
// }
// 
// Path: api/src/main/java/javax/observer/Property.java
// public interface Property<V> extends Observable<V> {
// 
//     /**
//      * Replaces the internal value with the given new value. This should end in calling the
//      * {@link ValueChangeListener#valueChanged(ValueChangeEvent)} method on all registered
//      * listeners.
//      * @param value the new value
//      */
//     void setValue(V value);
// }


import com.guigarage.binding.SwingBinding;
import com.guigarage.observer.BasicProperty;
import javax.observer.Property;
import javax.swing.JTextField;
package com.guigarage.examples;



public class SwingBindingExample {

    public static void main(String[] args) {

        Property<String> databaseBackgroundProperty = new BasicProperty<>();
        JTextField textField = new JTextField();

// Path: impl/src/main/java/com/guigarage/binding/SwingBinding.java
// public class SwingBinding {
// 
//     private static Executor backgroundExecutor = Executors.newSingleThreadExecutor();
// 
//     public static <T> ConvertableBidirectionalBindable<T> bind(final Component component, final String attribute) {
//         return new ConvertableBidirectionalBindable<T>() {
// 
//             private AtomicBoolean bindingCalled = new AtomicBoolean(false);
// 
//             private Consumer<Throwable> errorHandler = e -> e.printStackTrace();
// 
//             private Lock bindingLock = new ReentrantLock();
// 
//             private <U> U callLocked(Supplier<U> supplier) {
//                 bindingLock.lock();
//                 try {
//                     return supplier.get();
//                 } finally {
//                     bindingLock.unlock();
//                 }
//             }
// 
//             private void callLocked(Runnable runnable) {
//                 callLocked(() -> {
//                     runnable.run();
//                     return null;
//                 });
//             }
// 
//             @Override
//             public <U> Subscription bidirectionalTo(Property<U> property, Function<U, T> converter, Function<T, U> converter2) {
//                 try {
//                     final PropertyDescriptor propertyDescriptor = new PropertyDescriptor(attribute, component.getClass());
//                     final PropertyEditor propertyEditor = propertyDescriptor.createPropertyEditor(component);
//                     Subscription subscription = bind(property, converter, propertyEditor);
// 
//                     PropertyChangeListener listener = e -> {
//                         if (!bindingCalled.get()) {
//                             bindingCalled.set(true);
//                             try {
//                                 backgroundExecutor.execute(() -> {
//                                     callLocked(() -> {
//                                         try {
//                                             property.setValue(converter2.apply((T) e.getNewValue()));
//                                         } catch (Exception ex) {
//                                             SwingUtilities.invokeLater(() -> {
//                                                 errorHandler.accept(ex);
//                                             });
//                                         }
//                                     });
//                                 });
//                             } catch (Exception e1) {
//                                 errorHandler.accept(e1);
//                             } finally {
//                                 bindingCalled.set(false);
//                             }
//                         }
//                     };
// 
//                     component.addPropertyChangeListener(listener);
// 
//                     return () -> {
//                         component.removePropertyChangeListener(listener);
//                         subscription.unsubscribe();
//                     };
//                 } catch (Exception e1) {
//                     throw new RuntimeException("Can not bind!", e1);
//                 }
//             }
// 
//             @Override
//             public <U> Subscription to(Observable<U> observable, Function<U, T> converter) {
//                 try {
//                     final PropertyDescriptor propertyDescriptor = new PropertyDescriptor(attribute, component.getClass());
//                     final PropertyEditor propertyEditor = propertyDescriptor.createPropertyEditor(component);
//                     return bind(observable, converter, propertyEditor);
//                 } catch (Exception e1) {
//                     throw new RuntimeException("Can not bind!", e1);
//                 }
//             }
// 
//             private <U> Subscription bind(Observable<U> observable, Function<U, T> converter, PropertyEditor propertyEditor) {
//                 return observable.onChanged(e -> {
//                     callLocked(() -> {
//                         try {
//                             SwingUtilities.invokeAndWait(() -> {
//                                 if (!bindingCalled.get()) {
//                                     bindingCalled.set(true);
//                                     try {
//                                         propertyEditor.setValue(converter.apply(e.getValue()));
//                                     } catch (Exception e1) {
//                                         errorHandler.accept(e1);
//                                     } finally {
//                                         bindingCalled.set(false);
//                                     }
//                                 }
//                             });
//                         } catch (Exception e1) {
//                             SwingUtilities.invokeLater(() -> {
//                                 errorHandler.accept(e1);
//                             });
//                         }
//                     });
//                 });
//             }
// 
//             @Override
//             public ConvertableBindable<T> withErrorHandler(Consumer<Throwable> handler) {
//                 this.errorHandler = handler;
//                 return this;
//             }
// 
//         };
//     }
// }
// 
// Path: impl/src/main/java/com/guigarage/observer/BasicProperty.java
// public class BasicProperty<V> extends BasicObservable<V> implements Property<V> {
// 
//     @Override
//     public void setValue(V value) {
//         updateValue(value);
//     }
// }
// 
// Path: api/src/main/java/javax/observer/Property.java
// public interface Property<V> extends Observable<V> {
// 
//     /**
//      * Replaces the internal value with the given new value. This should end in calling the
//      * {@link ValueChangeListener#valueChanged(ValueChangeEvent)} method on all registered
//      * listeners.
//      * @param value the new value
//      */
//     void setValue(V value);
// }


// Path: impl/src/main/java/com/guigarage/examples/SwingBindingExample.java
import com.guigarage.binding.SwingBinding;
import com.guigarage.observer.BasicProperty;
import javax.observer.Property;
import javax.swing.JTextField;

package com.guigarage.examples;



public class SwingBindingExample {

    public static void main(String[] args) {

        Property<String> databaseBackgroundProperty = new BasicProperty<>();
        JTextField textField = new JTextField();

        SwingBinding.<String>bind(textField, "text").bidirectionalTo(databaseBackgroundProperty);