Mercurial > hg4j
changeset 356:91d75e1bac9f
Consistent approach to deal with adaptable objects. Give adaptable precedence over instanceof to allow conditional response when classes do implement desired interface
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Tue, 06 Dec 2011 14:25:52 +0100 |
parents | f2c11fe7f3e9 |
children | dfb8405d996f |
files | src/org/tmatesoft/hg/core/HgCatCommand.java src/org/tmatesoft/hg/internal/FilterByteChannel.java src/org/tmatesoft/hg/internal/NewlineFilter.java src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java src/org/tmatesoft/hg/repo/Revlog.java src/org/tmatesoft/hg/util/Adaptable.java src/org/tmatesoft/hg/util/CancelSupport.java src/org/tmatesoft/hg/util/ProgressSupport.java |
diffstat | 8 files changed, 71 insertions(+), 51 deletions(-) [+] |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgCatCommand.java Tue Dec 06 12:57:21 2011 +0100 +++ b/src/org/tmatesoft/hg/core/HgCatCommand.java Tue Dec 06 14:25:52 2011 +0100 @@ -205,13 +205,7 @@ if (CancelSupport.class == adapterClass) { return adapterClass.cast(cancelHelper); } - if (delegate instanceof Adaptable) { - return ((Adaptable) delegate).getAdapter(adapterClass); - } - if (adapterClass.isInstance(delegate)) { - return adapterClass.cast(delegate); - } - return null; + return Adaptable.Factory.getAdapter(delegate, adapterClass, null); } } }
--- a/src/org/tmatesoft/hg/internal/FilterByteChannel.java Tue Dec 06 12:57:21 2011 +0100 +++ b/src/org/tmatesoft/hg/internal/FilterByteChannel.java Tue Dec 06 14:25:52 2011 +0100 @@ -59,9 +59,11 @@ public <T> T getAdapter(Class<T> adapterClass) { if (adapterClass == Preview.class) { ArrayList<Preview> previewers = new ArrayList<Preview>(filters.length); + Adaptable.Factory<Preview> factory = new Adaptable.Factory<Preview>(Preview.class); for (Filter f : filters) { - if (f instanceof Preview /*FIXME or getAdapter != null*/) { - previewers.add((Preview) f); + Preview p = factory.get(f); + if (p != null) { + previewers.add(p); } } if (!previewers.isEmpty()) { @@ -71,13 +73,7 @@ } // fall through to let delegate answer } - if (delegate instanceof Adaptable) { - return ((Adaptable) delegate).getAdapter(adapterClass); - } - if (adapterClass != null && adapterClass.isInstance(delegate)) { - return adapterClass.cast(delegate); - } - return null; + return Adaptable.Factory.getAdapter(delegate, adapterClass, null); } private static class PreviewSupport implements Preview {
--- a/src/org/tmatesoft/hg/internal/NewlineFilter.java Tue Dec 06 12:57:21 2011 +0100 +++ b/src/org/tmatesoft/hg/internal/NewlineFilter.java Tue Dec 06 14:25:52 2011 +0100 @@ -31,6 +31,7 @@ import org.tmatesoft.hg.core.HgBadStateException; import org.tmatesoft.hg.repo.HgInternals; import org.tmatesoft.hg.repo.HgRepository; +import org.tmatesoft.hg.util.Adaptable; import org.tmatesoft.hg.util.Path; /** @@ -38,7 +39,7 @@ * @author Artem Tikhomirov * @author TMate Software Ltd. */ -public class NewlineFilter implements Filter, Preview { +public class NewlineFilter implements Filter, Preview, Adaptable { // if processInconsistent is false, filter simply pass incorrect newline characters (single \r or \r\n on *nix and single \n on Windows) as is, // i.e. doesn't try to convert them into appropriate newline characters. @@ -65,8 +66,8 @@ } public ByteBuffer filter(ByteBuffer src) { - if (!previewDone) { - throw new HgBadStateException("This filter requires preview operation prior to actual filtering"); + if (!processInconsistent && !previewDone) { + throw new HgBadStateException("This filter requires preview operation prior to actual filtering when eol.only-consistent is true"); } if (!processInconsistent && foundLoneLF && foundCRLF) { // do not process inconsistent newlines @@ -86,6 +87,18 @@ } } + public <T> T getAdapter(Class<T> adapterClass) { + // conditionally through getAdapter + if (Preview.class == adapterClass) { + // when processInconsistent is false, we need to preview data stream to ensure line terminators are consistent. + // otherwise, no need to look into the stream + if (!processInconsistent) { + return adapterClass.cast(this); + } + } + return null; + } + private boolean prevBufLastByteWasCR = false; private boolean previewDone = false; @@ -93,7 +106,6 @@ previewDone = true; // guard if (processInconsistent) { // gonna handle them anyway, no need to check. TODO Do not implement Preview directly, but rather - // conditionally through getAdapter when processInconsistent is false (sic!) return; } if (foundLoneLF && foundCRLF) {
--- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Tue Dec 06 12:57:21 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Tue Dec 06 14:25:52 2011 +0100 @@ -40,6 +40,7 @@ import org.tmatesoft.hg.internal.ManifestRevision; import org.tmatesoft.hg.internal.PathScope; import org.tmatesoft.hg.internal.Preview; +import org.tmatesoft.hg.util.Adaptable; import org.tmatesoft.hg.util.ByteChannel; import org.tmatesoft.hg.util.CancelledException; import org.tmatesoft.hg.util.FileInfo; @@ -470,7 +471,7 @@ is = f.newInputChannel(); ByteBuffer fb = ByteBuffer.allocate(min(1 + data.length * 2 /*to fit couple of lines appended; never zero*/, 8192)); FilterByteChannel filters = new FilterByteChannel(check, repo.getFiltersFromWorkingDirToRepo(p)); - Preview preview = filters.getAdapter(Preview.class); + Preview preview = Adaptable.Factory.getAdapter(filters, Preview.class, null); if (preview != null) { while (is.read(fb) != -1) { fb.flip();
--- a/src/org/tmatesoft/hg/repo/Revlog.java Tue Dec 06 12:57:21 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/Revlog.java Tue Dec 06 14:25:52 2011 +0100 @@ -253,8 +253,8 @@ if (end == TIP) { end = lastRev; } - final RevisionInspector revisionInsp = getAdapter(inspector, RevisionInspector.class); - final ParentInspector parentInsp = getAdapter(inspector, ParentInspector.class); + final RevisionInspector revisionInsp = Adaptable.Factory.getAdapter(inspector, RevisionInspector.class, null); + final ParentInspector parentInsp = Adaptable.Factory.getAdapter(inspector, ParentInspector.class, null); final Nodeid[] allRevisions = parentInsp == null ? null : new Nodeid[end - start + 1]; content.iterate(start, end, false, new RevlogStream.Inspector() { @@ -273,15 +273,6 @@ } }); } - private static <T> T getAdapter(Object o, Class<T> adapterClass) { - if (adapterClass.isInstance(o)) { - return adapterClass.cast(o); - } - if (o instanceof Adaptable) { - return ((Adaptable) o).getAdapter(adapterClass); - } - return null; - } /** * MARKER @@ -624,7 +615,7 @@ prepare(revisionNumber, da); // XXX perhaps, prepare shall return DA (sliced, if needed) final ProgressSupport progressSupport = ProgressSupport.Factory.get(sink); ByteBuffer buf = ByteBuffer.allocate(actualLen > 8192 ? 8192 : actualLen); - Preview p = getAdapter(sink, Preview.class); + Preview p = Adaptable.Factory.getAdapter(sink, Preview.class, null); if (p != null) { progressSupport.start(2 * da.length()); while (!da.isEmpty()) {
--- a/src/org/tmatesoft/hg/util/Adaptable.java Tue Dec 06 12:57:21 2011 +0100 +++ b/src/org/tmatesoft/hg/util/Adaptable.java Tue Dec 06 14:25:52 2011 +0100 @@ -25,4 +25,44 @@ public interface Adaptable { <T> T getAdapter(Class<T> adapterClass); + + class Factory<T> { + + private final Class<T> adapterClass; + + public Factory(Class<T> adapterClass) { + assert adapterClass != null; + this.adapterClass = adapterClass; + } + + public T get(Object target) { + return getAdapter(target, adapterClass, null); + } + + public T get(Object target, T defaultValue) { + return getAdapter(target, adapterClass, defaultValue); + } + + /** + * Try to adapt target to specified class, resort to defaultValue when not possible. + * Instance lookup order is as follows: first, target is checked for being {@link Adaptable} and, if yes, + * consulted for adapter. Then, plain {@link Class#isInstance(Object) instanceof} checks if target itself is + * of desired type. {@link Adaptable} check comes first to allow classed that are in fact <code>instanceof</code> + * desired type to respond to the demand conditionally + * + * @param target object to adapt, <code>null</code> value, although meaningless, is tolerable. + * @param adapterClass desired target class + * @param defaultValue value to use if target cannot be adapted to desired class, may be <code>null</code> + * @return instance of the desired class + */ + public static <C> C getAdapter(Object target, Class<C> adapterClass, C defaultValue) { + if (target instanceof Adaptable) { + return ((Adaptable) target).getAdapter(adapterClass); + } + if (adapterClass.isInstance(target)) { + return adapterClass.cast(target); + } + return defaultValue; + } + } }
--- a/src/org/tmatesoft/hg/util/CancelSupport.java Tue Dec 06 12:57:21 2011 +0100 +++ b/src/org/tmatesoft/hg/util/CancelSupport.java Tue Dec 06 14:25:52 2011 +0100 @@ -54,16 +54,7 @@ } public static CancelSupport get(Object target, CancelSupport defaultValue) { - if (target instanceof CancelSupport) { - return (CancelSupport) target; - } - if (target instanceof Adaptable) { - CancelSupport cs = ((Adaptable) target).getAdapter(CancelSupport.class); - if (cs != null) { - return cs; - } - } - return defaultValue; + return Adaptable.Factory.getAdapter(target, CancelSupport.class, defaultValue); } }
--- a/src/org/tmatesoft/hg/util/ProgressSupport.java Tue Dec 06 12:57:21 2011 +0100 +++ b/src/org/tmatesoft/hg/util/ProgressSupport.java Tue Dec 06 14:25:52 2011 +0100 @@ -37,14 +37,9 @@ * @return support object extracted from target or an empty, no-op implementation */ public static ProgressSupport get(Object target) { - if (target instanceof ProgressSupport) { - return (ProgressSupport) target; - } - if (target instanceof Adaptable) { - ProgressSupport ps = ((Adaptable) target).getAdapter(ProgressSupport.class); - if (ps != null) { - return ps; - } + ProgressSupport ps = Adaptable.Factory.getAdapter(target, ProgressSupport.class, null); + if (ps != null) { + return ps; } return new ProgressSupport() { public void start(int totalUnits) {