Jelajahi Sumber

rename: Bitmask into MaskFactory
new: MaskSet
rename: UserStore#match into #find
fix: local build does not require javadoc
new: scripts & pmd rules

Ranides Atterwim 4 tahun lalu
induk
melakukan
242c1e6904

+ 185 - 0
assira.core/src/main/java/net/ranides/assira/collection/sets/MaskSet.java

@@ -0,0 +1,185 @@
+package net.ranides.assira.collection.sets;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * This class extends standard Set collection, providing additional functionality.
+ * - offers conversion of set into int
+ * - offers fast conversion into mutable or immutable MaskSet
+ * <p>
+ * This class can be created directly. You must use MaskFactory to obtain instances of this class.
+ *
+ * @param <T> type of
+ */
+public abstract class MaskSet<T> extends AbstractSet<T> {
+
+    protected final MaskFactory<T> factory;
+
+    protected MaskSet(MaskFactory<T> factory) {
+        this.factory = factory;
+    }
+
+    /**
+     * Converts this mask into int value.
+     *
+     * @return int
+     */
+    public abstract int intValue();
+
+    /**
+     * Converts this mask into mutable set.
+     *
+     * @return new mask
+     */
+    public final MaskSet<T> toMutable() {
+        return new MutableSet<>(factory, intValue());
+    }
+
+    /**
+     * Converts this mask into immutable set.
+     *
+     * @return new mask
+     */
+    public final MaskSet<T> toImmutable() {
+        return new ImmutableSet<>(factory, intValue());
+    }
+
+    @Override
+    public final Iterator<T> iterator() {
+        return new ConstIterator<>(factory, intValue());
+    }
+
+    @Override
+    public final int size() {
+        return Integer.bitCount(intValue());
+    }
+
+    @Override
+    public final boolean contains(Object object) {
+        if (!factory.type.isInstance(object)) {
+            return false;
+        }
+        int v = factory.objectToInt(object);
+        return v == (intValue() & v);
+    }
+
+    @Override
+    public final boolean containsAll(Collection<?> object) {
+        if (object instanceof MaskSet) {
+            MaskSet<?> that = (MaskSet<?>) object;
+            if (this.factory == that.factory) {
+                return that.intValue() == (this.intValue() & that.intValue());
+            }
+        }
+        return super.containsAll(object);
+    }
+
+    static class ImmutableSet<T> extends MaskSet<T> {
+
+        private final int values;
+
+        public ImmutableSet(MaskFactory<T> factory, int values) {
+            super(factory);
+            this.values = values;
+        }
+
+        @Override
+        public int intValue() {
+            return values;
+        }
+
+    }
+
+    static class MutableSet<T> extends MaskSet<T> {
+
+        private int values;
+
+        public MutableSet(MaskFactory<T> factory, int values) {
+            super(factory);
+            this.values = values;
+        }
+
+        @Override
+        public int intValue() {
+            return values;
+        }
+
+        @Override
+        public boolean remove(Object value) {
+            if(!factory.type.isInstance(value)) {
+                return false;
+            }
+
+            int iv = factory.objectToInt(value);
+            if(0 == (values & iv)) {
+                return false;
+            }
+            values &= ~iv;
+            return true;
+        }
+
+        @Override
+        public boolean add(T value) {
+            return iadd(factory.genericToInt(value));
+        }
+
+        @Override
+        public boolean addAll(Collection<? extends T> object) {
+            if(object instanceof MaskSet) {
+                MaskSet<?> that = (MaskSet<?>)object;
+                if(this.factory == that.factory) {
+                    return iadd(that.intValue());
+                }
+            }
+            return super.addAll(object);
+        }
+
+        private boolean iadd(int iv) {
+            if(iv == (values & iv)) {
+                return false;
+            }
+            values |= iv;
+            return true;
+        }
+
+    }
+
+    private static final class ConstIterator<T> implements Iterator<T> {
+
+        private final MaskFactory<T> factory;
+        private int value;
+        private int index;
+
+        public ConstIterator(MaskFactory<T> factory, int value) {
+            this.factory = factory;
+            this.value = value;
+            this.index = 0;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return 0 != value;
+        }
+
+        @Override
+        public T next() {
+            try {
+                while(value!=0) {
+                    T item = factory.universe[index++];
+                    int iv = factory.genericToInt(item);
+                    if( 0 != (value & iv) ) {
+                        value &= ~iv;
+                        return item;
+                    }
+                }
+            } catch(IndexOutOfBoundsException cause) {
+                throw new NoSuchElementException(factory.unknownValueMessage(value));
+            }
+            throw new NoSuchElementException();
+        }
+
+    }
+}

+ 43 - 4
assira.core/src/main/java/net/ranides/assira/credentials/BasicUserStore.java

@@ -1,3 +1,10 @@
+/*
+ * @author Ranides Atterwim {@literal <ranides@gmail.com>}
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+
 package net.ranides.assira.credentials;
 
 import net.ranides.assira.collection.prototype.GenericKey;
@@ -11,12 +18,21 @@ import java.net.URI;
 import java.util.Optional;
 
 /**
- * @author msieron
+ * Simple, in-memory user store.
+ * It supports fast search by URI, matching UserProperty.HOST & UserProperty.PORT.
+ * It supports fast search by name, matching UserProperty.ACCOUNT.
+ *
+ * This store is mutable. You can add users at any time.
+ *
+ * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
 public class BasicUserStore implements UserStore {
 
     private final IQueryMap<GenericMap<String>> tree;
 
+    /**
+     * Creates new empty store
+     */
     public BasicUserStore() {
         tree = new IQueryMapTree<>();
         index(UserProperty.ACCOUNT);
@@ -28,8 +44,16 @@ public class BasicUserStore implements UserStore {
         tree.index(key.id(), key);
     }
 
+    /**
+     * Finds users matching URI. Extracts from URI host & port and compares it with fields:
+     *  - UserProperty.HOST
+     *  - UserProperty.PORT
+     *
+     * @param uri uri
+     * @return users
+     */
     @Override
-    public CQuery<GenericMap<String>> match(URI uri) {
+    public CQuery<GenericMap<String>> find(URI uri) {
         Optional<String> login = URIUtils.getLogin(uri);
 
         if(login.isPresent()) {
@@ -50,11 +74,26 @@ public class BasicUserStore implements UserStore {
         return u.getOptional(UserProperty.URI).map(p -> p.test(uri)).orElse(true);
     }
 
+    /**
+     * Finds users with UserProperty.ACCOUNT equal to specified query value.
+     *
+     * @param query query
+     * @return users
+     */
     @Override
-    public CQuery<GenericMap<String>> find(String user) {
-        return tree.find().eq(UserProperty.ACCOUNT, user);
+    public CQuery<GenericMap<String>> find(String query) {
+        return tree.find().eq(UserProperty.ACCOUNT, query);
     }
 
+    /**
+     * Inserts user into userstore. Below properties are used in queries:
+     *  - UserProperty.ACCOUNT
+     *  - UserProperty.HOST
+     *  - UserProperty.PORT
+     *
+     * @param user user
+     * @return this
+     */
     public BasicUserStore add(GenericMap<String> user) {
         tree.put(user);
         return this;

+ 28 - 4
assira.core/src/main/java/net/ranides/assira/credentials/UserStore.java

@@ -11,13 +11,37 @@ import net.ranides.assira.collection.prototype.GenericMap;
 import net.ranides.assira.collection.query.CQuery;
 
 /**
+ * Container for user credentials.
+ * Offers two functionalities: find users by query & find users by matching URI
+ *
+ * For example, maven credential for "servers" can be represented by this store:
+ *  - "find by query" will search by "username" directly inside "settings.xml"
+ *  - "find by URL" will search inside "pom.xml" for "server.id" matching URL
+ *    then it will use this "server.id" to load credentials from "settings.xml"
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
 public interface UserStore {
-    
-    CQuery<GenericMap<String>> match(URI uri);
-    
-    CQuery<GenericMap<String>> find(String user);
+
+    /**
+     * Find all users matching specified ID.
+     * Quite often credentials are associated with specific domain, you can use this function
+     * to find them.
+     *
+     * @param uri uri
+     * @return list of matching users
+     */
+    CQuery<GenericMap<String>> find(URI uri);
+
+    /**
+     * Find all users matching query.
+     * Most probably, userstore will return users with "login" identical to specified argument.
+     * Please note, that this semantic is not guaranteed.
+     * For example, some stores would support wildcards, check emails, full names, aliases, etc
+     *
+     * @param query query
+     * @return list of matching users
+     */
+    CQuery<GenericMap<String>> find(String query);
     
 }

+ 6 - 5
assira.core/src/main/java/net/ranides/assira/io/uri/URIFlags.java

@@ -8,7 +8,8 @@ package net.ranides.assira.io.uri;
 
 import java.io.IOException;
 import java.util.Set;
-import net.ranides.assira.collection.sets.Bitmask;
+import net.ranides.assira.collection.sets.MaskFactory;
+import net.ranides.assira.collection.sets.MaskSet;
 
 /**
  *
@@ -28,7 +29,7 @@ public enum URIFlags {
     SEEK        (0x0000_0200),
     ;
     
-    private static final Bitmask<URIFlags> MAP = new Bitmask<>(URIFlags.values(), a -> a.mask);
+    private static final MaskFactory<URIFlags> MAP = new MaskFactory<>(URIFlags.values(), a -> a.mask);
     
     private final int mask;
 
@@ -40,15 +41,15 @@ public enum URIFlags {
         return ustream.flags().contains(this);
     }
     
-    public static Set<URIFlags> collect(URIFlags... flags) {
+    public static MaskSet<URIFlags> collect(URIFlags... flags) {
         return MAP.collect(flags);
     }
     
-    public static Set<URIFlags> constant(URIFlags... flags) {
+    public static MaskSet<URIFlags> constant(URIFlags... flags) {
         return MAP.constant(flags);
     }
     
-    public static Set<URIFlags> clone(Set<URIFlags> flags) {
+    public static MaskSet<URIFlags> clone(Set<URIFlags> flags) {
         return MAP.clone(flags);
     }
     

+ 6 - 6
assira.core/src/main/java/net/ranides/assira/io/uri/URIResolver.java

@@ -103,13 +103,13 @@ public final class URIResolver {
         private final List<UserStore> stores = new RTList<>(new UserStore[]{new ExtractStore()});
 
         @Override
-        public CQuery<GenericMap<String>> match(URI uri) {
-            return CQuery.from().collection(stores).unfold(s -> s.match(uri));
+        public CQuery<GenericMap<String>> find(URI uri) {
+            return CQuery.from().collection(stores).unfold(s -> s.find(uri));
         }
 
         @Override
-        public CQuery<GenericMap<String>> find(String user) {
-            return CQuery.from().collection(stores).unfold(s -> s.find(user));
+        public CQuery<GenericMap<String>> find(String query) {
+            return CQuery.from().collection(stores).unfold(s -> s.find(query));
         }
         
         public void add(UserStore store) {
@@ -121,7 +121,7 @@ public final class URIResolver {
     private static final class ExtractStore implements UserStore {
         
         @Override
-        public CQuery<GenericMap<String>> match(URI uri) {
+        public CQuery<GenericMap<String>> find(URI uri) {
             GenericMap<String> a = new OpenGenericMap<>();
             a.put(UserProperty.LOGIN, URIUtils.getLogin(uri));
             a.put(UserProperty.PASSWORD, URIUtils.getPassword(uri));
@@ -129,7 +129,7 @@ public final class URIResolver {
         }
 
         @Override
-        public CQuery<GenericMap<String>> find(String user) {
+        public CQuery<GenericMap<String>> find(String query) {
             return CQuery.empty();
         }
     

+ 1 - 1
assira.core/src/main/java/net/ranides/assira/io/uri/impl/CFTPHandler.java

@@ -281,7 +281,7 @@ public class CFTPHandler implements URIHandler {
         
         public FTPHostName(URI uri, UserStore users) {
             host = uri.getHost();
-            Optional<GenericMap<String>> uis = users.match(uri).last();
+            Optional<GenericMap<String>> uis = users.find(uri).last();
             if(uis.isPresent()) {
                 GenericMap<String> ui = uis.get();
                 user = ui.getOptional(UserProperty.LOGIN);

+ 1 - 1
assira.core/src/main/java/net/ranides/assira/io/uri/impl/CHTTPHandler.java

@@ -195,7 +195,7 @@ public class CHTTPHandler implements URIHandler {
             c.setConnectTimeout(CONNECT_TIMEOUT);
             c.setRequestMethod(method);
 
-            resolver.users().match(uri).first().ifPresent(v -> setAuthorizationHeader(c, v));
+            resolver.users().find(uri).first().ifPresent(v -> setAuthorizationHeader(c, v));
             return c;
         }
 

+ 6 - 5
assira.core/src/main/java/net/ranides/assira/reflection/IAttributes.java

@@ -1,11 +1,12 @@
 package net.ranides.assira.reflection;
 
-import net.ranides.assira.collection.sets.Bitmask;
+import net.ranides.assira.collection.sets.MaskFactory;
+import net.ranides.assira.collection.sets.MaskSet;
 import net.ranides.assira.reflection.util.ClassTraits;
 
 import java.lang.reflect.*;
 import java.util.Objects;
-import java.util.Set;
+
 import static net.ranides.assira.reflection.IAttribute.*;
 
 public class IAttributes {
@@ -16,15 +17,15 @@ public class IAttributes {
 
     private static final int ACCESS_ANY = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
 
-    private static final Bitmask<IAttribute> MAP = new Bitmask<>(IAttribute.values(), a -> a.mask);
+    private static final MaskFactory<IAttribute> MAP = new MaskFactory<>(IAttribute.values(), a -> a.mask);
 
     public static final IAttributes EMPTY = new IAttributes(0,0).immutable();
 
     private int reflective;
 
-    private final Set<IAttribute> values;
+    private final MaskSet<IAttribute> values;
 
-    private IAttributes(int reflective, Set<IAttribute> values) {
+    private IAttributes(int reflective, MaskSet<IAttribute> values) {
         this.reflective = reflective;
         this.values = values;
     }

+ 9 - 9
assira.core/src/test/java/net/ranides/assira/credentials/BasicUserStoreTest.java

@@ -51,17 +51,17 @@ public class BasicUserStoreTest {
         }});
 
 
-        assertEquals(Arrays.asList("ranides"), store.match(new URI("http://home@host.net/info.htm")).map(UserProperty.LOGIN).sort().list() );
-        assertEquals(Arrays.asList("john"), store.match(new URI("http://home@host.org/info.asp")).map(UserProperty.LOGIN).sort().list() );
+        assertEquals(Arrays.asList("ranides"), store.find(new URI("http://home@host.net/info.htm")).map(UserProperty.LOGIN).sort().list() );
+        assertEquals(Arrays.asList("john"), store.find(new URI("http://home@host.org/info.asp")).map(UserProperty.LOGIN).sort().list() );
 
-        assertEquals(Arrays.asList("annette"), store.match(new URI("http://hidden@host/info.asp")).map(UserProperty.LOGIN).sort().list() );
-        assertEquals(Arrays.asList("annette"), store.match(new URI("ftp://host/info.asp")).map(UserProperty.LOGIN).sort().list() );
-        assertEquals(Arrays.asList("annette", "joanne"), store.match(new URI("http://host/info.asp")).map(UserProperty.LOGIN).sort().list() );
+        assertEquals(Arrays.asList("annette"), store.find(new URI("http://hidden@host/info.asp")).map(UserProperty.LOGIN).sort().list() );
+        assertEquals(Arrays.asList("annette"), store.find(new URI("ftp://host/info.asp")).map(UserProperty.LOGIN).sort().list() );
+        assertEquals(Arrays.asList("annette", "joanne"), store.find(new URI("http://host/info.asp")).map(UserProperty.LOGIN).sort().list() );
 
-        assertEquals(Arrays.asList("anne"), store.match(new URI("http://hidden@domain/info.htm")).map(UserProperty.LOGIN).sort().list() );
-        assertEquals(Arrays.asList("anne", "joanne"), store.match(new URI("http://host/info.htm")).map(UserProperty.LOGIN).sort().list() );
-        assertEquals(Arrays.asList("anne", "joanne"), store.match(new URI("http://domain/info.htm")).map(UserProperty.LOGIN).sort().list() );
-        assertEquals(Arrays.asList("joanne"), store.match(new URI("http://custom@domain/info.htm")).map(UserProperty.LOGIN).sort().list() );
+        assertEquals(Arrays.asList("anne"), store.find(new URI("http://hidden@domain/info.htm")).map(UserProperty.LOGIN).sort().list() );
+        assertEquals(Arrays.asList("anne", "joanne"), store.find(new URI("http://host/info.htm")).map(UserProperty.LOGIN).sort().list() );
+        assertEquals(Arrays.asList("anne", "joanne"), store.find(new URI("http://domain/info.htm")).map(UserProperty.LOGIN).sort().list() );
+        assertEquals(Arrays.asList("joanne"), store.find(new URI("http://custom@domain/info.htm")).map(UserProperty.LOGIN).sort().list() );
     }
 
 }

+ 33 - 23
assira.jdk8/pom.xml

@@ -34,32 +34,42 @@
                     </execution>
                 </executions>
             </plugin>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <version>3.2.0</version>
-                <executions>
-                    <execution>
-                        <id>attach-artifacts</id>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>attach-artifact</goal>
-                        </goals>
-                        <configuration>
-                            <artifacts>
-                                <artifact>
-                                    <file>../assira.core8/target/assira.core8-${project.version}-javadoc.jar</file>
-                                    <type>jar</type>
-                                    <classifier>javadoc</classifier>
-                                </artifact>
-                            </artifacts>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
     </build>
 
+    <profiles>
+        <profile>
+            <id>release</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>build-helper-maven-plugin</artifactId>
+                        <version>3.2.0</version>
+                        <executions>
+                            <execution>
+                                <id>attach-artifacts</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>attach-artifact</goal>
+                                </goals>
+                                <configuration>
+                                    <artifacts>
+                                        <artifact>
+                                            <file>../assira.core8/target/assira.core8-${project.version}-javadoc.jar</file>
+                                            <type>jar</type>
+                                            <classifier>javadoc</classifier>
+                                        </artifact>
+                                    </artifacts>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>

assira.rules/javadoc.xml → rules/javadoc.xml


+ 2 - 5
deploy-me.bat

@@ -1,22 +1,19 @@
 @echo off
 call jdk8
-call mvn clean deploy -P common,jdk8,release
+call mvn %* deploy -P common,jdk8,release
 if errorlevel 1 goto fail
 
 call jdk11
-call mvn clean deploy -P jdk11,release
+call mvn %* deploy -P jdk11,release
 if errorlevel 1 goto fail
 
 goto success
-
 :fail
     echo ERROR
     goto end
-
 :success
     echo SUCCESS
     goto end
-
 :end
 
 

+ 19 - 0
scripts/install-core.bat

@@ -0,0 +1,19 @@
+@echo off
+call jdk8
+call mvn -f ../assira.core/pom.xml %* install -P jdk8
+if errorlevel 1 goto fail
+call mvn -f ../assira.core8/pom.xml %* install -P jdk8
+if errorlevel 1 goto fail
+
+call jdk11
+call mvn -f ../assira.core11/pom.xml %* install -P jdk8
+if errorlevel 1 goto fail
+
+goto success
+:fail
+    echo ERROR
+    goto end
+:success
+    echo SUCCESS
+    goto end
+:end

+ 3 - 0
scripts/install-jdk11.bat

@@ -0,0 +1,3 @@
+@echo off
+call jdk11
+call mvn -f ../pom.xml %* install -P jdk11

+ 3 - 0
scripts/install-jdk8.bat

@@ -0,0 +1,3 @@
+@echo off
+call jdk8
+call mvn -f ../pom.xml %* install -P common,jdk8