Monday, April 29, 2013

Moving a git repository to the subdirectory of another repository

How do I move a git repository to be the subdirectory of another repository? is a question answered umpteen times, and all answers vary somewhat. For my needs, this suffices:

#!/bin/bash

case $# in
  3 ) old_repo=$1 new_repo=$2 new_name=$3 ;;
  * ) echo "$0: old_repo new_repo new_name" ; exit 2 ;;
esac

set -e

trap 'rm -rf $old_work $new_work' EXIT
old_work=$(mktemp -d)
new_work=$(mktemp -d)
git clone $old_repo $old_work
git clone $new_repo $new_work

cd $old_work
# If new_name contains commas, edit the sed command accordingly
git filter-branch --index-filter 'git ls-files -s | sed "s,\t\"*,&'$new_name'/," | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD

cd $new_work
git remote add $new_name $old_work
git pull $new_name master
git push

-XshowSettings

A java flag I hadn't noticed before but wish I had: -XshowSettings. It dumps out the system properties and a guess at which VM to use (server v. client), among other things. Look here for more magic -X flags.

Monday, April 15, 2013

More good Java 8, living with null

Edwin Dalorzo posts wonderfully on Java 8 Optional Objects: what is the problem, how it is handled in other languages, what Java 8 does about it. It all boils down to the "billion dollar mistake": null.

Thursday, April 11, 2013

Moving, but not the blog

Monday morning, April 1st, my family and I relocate for work to Manila from Houston. My employer, Macquarie Bank, is a conservative, successful investment bank from Australia. 2008 brought difficulties for many firms in the banking industry; for Macquarie it brought opportunity.

I encourage anyone looking for the right work environment to consider Macquarie. For many of my mates this is their first and only job out of college, writing building impressive systems from solid code. It is my only job as satisfying as ThoughtWorks.

Only my family and me are moving. binkley's BLOG remains where it is.

Map view of list key-value pairs in Java

Long time no code.

Example use

import ListMap;

import javax.annotation.Nonnull;
import java.util.ArrayList;

import static java.util.Arrays.asList;

public class AttributesMap
        extends ListMap<FooItem, String, String> {
    public AttributesMap(final FooOperations foos, final String cookie) {
        super(new FooItems(foos, cookie), new FooItemConverter());
    }

    private static class FooItems
            extends ArrayList<FooItem> {
        private final FooOperations foos;
        private final String cookie;

        private FooItems(final FooOperations foos, final String cookie) {
            super(asList(foos.getAttributes(cookie)));
            this.foos = foos;
            this.cookie = cookie;
        }

        @Override
        public FooItem set(final int index, final FooItem element) {
            final FooItem oldElement = super.set(index, element);
            save();
            return oldElement;
        }

        @Override
        public void add(final int index, final FooItem element) {
            super.add(index, element);
            save();
        }

        @Override
        public FooItem remove(final int index) {
            final FooItem oldElement = super.remove(index);
            save();
            return oldElement;
        }

        private void save() {
            try {
                foos.setAttributes(cookie, toArray(new FooItem[size()]));
            } catch (final BadDataRef e) {
                throw new UserRuntimeException(e);
            }
        }
    }

    private static final class FooItemConverter
            implements Converter<FooItem, String, String> {
        @Nonnull
        @Override
        public FooItem toElement(@Nonnull final String key, final String value) {
            return new FooItem(key, value);
        }

        @Nonnull
        @Override
        public Entry<String, String> toEntry(@Nonnull final FooItem element) {
            return new SimpleEntry<>(element.tag, element.value);
        }
    }
}

ListMap utility class

import javax.annotation.Nonnull;
import javax.annotation.concurrent.NotThreadSafe;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.List;
import java.util.ListIterator;

/**
 * {@code ListMap} provides a read-write map view over a list of elements.  The elements must
 * provide a key-value pair structure; keys must {@link #equals(Object)} and {@link #hashCode()}.
 * <p/>
 * All map mutating methods also mutate the underlying list.  Mutating the underlying list also
 * mutates the map view.
 * <p/>
 * There is no synchronization; instances are not thread safe.
 *
 * @param <T> the type of list elements
 * @param <K> the type of map keys
 * @param <V> the type of map values
 *
 * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
 */
@NotThreadSafe
public class ListMap<T, K, V>
        extends AbstractMap<K, V> {
    private final List<T> elements;
    private final Converter<T, K, V> converter;

    /**
     * Creates a new {@code ListMap} for the given <var>elements</var> and <var>converter</var>.
     *
     * @param elements the list of elements underlying the map, never missing
     * @param converter the converter between elements and entry objects, never missing
     */
    public ListMap(@Nonnull final List<T> elements, @Nonnull final Converter<T, K, V> converter) {
        this.elements = elements;
        this.converter = converter;
    }

    /**
     * {@inheritDoc}
     * <p/>
     * Updates the underlying list of elements.
     */
    @Override
    public V put(final K key, final V value) {
        final ListIterator<T> lit = elements.listIterator();
        while (lit.hasNext()) {
            final T element = lit.next();
            final Entry<K, V> entry = converter.toEntry(element);
            if (entry.getKey().equals(key)) {
                elements.set(lit.nextIndex() - 1, converter.toElement(key, value));
                return entry.getValue();
            }
        }
        lit.add(converter.toElement(key, value));
        return null;
    }

    /**
     * {@inheritDoc}
     *
     * @return a specialized set view of the entries over the element list
     */
    @Override
    @Nonnull
    public ListMapSet entrySet() {
        return new ListMapSet();
    }

    /**
     * Exposes the underlying list of elements backing the map view.
     *
     * @return the element list, never missing
     */
    @Nonnull
    public List<T> elements() {
        return elements;
    }

    /**
     * Converts between elements and entry objects.
     *
     * @param <T> the type of list elements
     * @param <K> the type of map keys
     * @param <V> the type of map values
     */
    public static interface Converter<T, K, V> {
        /**
         * Converts to an element instance from a map <var>key</var>-<var>value</var> pair.
         *
         * @param key the map key, never missing
         * @param value the map value, optional
         *
         * @return the corresponding list element, never missing
         */
        @Nonnull
        T toElement(@Nonnull final K key, final V value);

        /**
         * Converts to a map entry instance from a list <var>element</var>.
         *
         * @param element the list element, never missing
         *
         * @return the corresponding map entry, never missing
         */
        @Nonnull
        Entry<K, V> toEntry(@Nonnull final T element);
    }

    /**
     * Backing set for {@link ListMap} exposed as a separate type so callers may access a {@link
     * #iterator() list iterator} and a list iterator {@link #iterator(int) offset by an index}.
     */
    public final class ListMapSet
            extends AbstractSet<Entry<K, V>> {
        /**
         * {@inheritDoc}
         *
         * @see java.util.List#listIterator()
         */
        @Override
        @Nonnull
        public ListMapIterator iterator() {
            return new ListMapIterator();
        }

        @Override
        public int size() {
            return elements.size();
        }

        @Override
        public boolean add(final Entry<K, V> entry) {
            return elements.add(converter.toElement(entry.getKey(), entry.getValue()));
        }

        /** @see List#listIterator(int) */
        @Nonnull
        public ListMapIterator iterator(final int index) {
            return new ListMapIterator(index);
        }

    }

    /**
     * Entry set iterator for {@link ListMapSet} exposed as a separate type.
     *
     * @see ListMapSet#iterator() list iterator
     * @see ListMapSet#iterator(int) offset by an index
     */
    public final class ListMapIterator
            implements ListIterator<Entry<K, V>> {
        private final ListIterator<T> it;

        public ListMapIterator() {
            it = elements.listIterator();
        }

        public ListMapIterator(final int index) {
            it = elements.listIterator(index);
        }

        @Override
        public boolean hasNext() {
            return it.hasNext();
        }

        @Override
        public Entry<K, V> next() {
            return new ListMapEntry(it.next());
        }

        @Override
        public boolean hasPrevious() {
            return it.hasPrevious();
        }

        @Override
        public Entry<K, V> previous() {
            return new ListMapEntry(it.previous());
        }

        @Override
        public int nextIndex() {
            return it.nextIndex();
        }

        @Override
        public int previousIndex() {
            return it.previousIndex();
        }

        @Override
        public void remove() {
            it.remove();
        }

        @Override
        public void set(final Entry<K, V> entry) {
            it.set(converter.toElement(entry.getKey(), entry.getValue()));
        }

        @Override
        public void add(final Entry<K, V> entry) {
            it.add(converter.toElement(entry.getKey(), entry.getValue()));
        }

        private class ListMapEntry
                implements Entry<K, V> {
            private final T element;

            ListMapEntry(final T element) {
                this.element = element;
            }

            @Override
            public K getKey() {
                return converter.toEntry(element).getKey();
            }

            @Override
            public V getValue() {
                return converter.toEntry(element).getValue();
            }

            @Override
            public V setValue(final V value) {
                final Entry<K, V> oldEntry = converter.toEntry(element);
                elements.set(nextIndex() - 1, converter.toElement(oldEntry.getKey(), value));
                return oldEntry.getValue();
            }
        }
    }
}