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) {