JSPWIKI-303: Acl / AclEntry SPI
diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/spi/AclsDSL.java b/jspwiki-api/src/main/java/org/apache/wiki/api/spi/AclsDSL.java
new file mode 100644
index 0000000..6fa3c8d
--- /dev/null
+++ b/jspwiki-api/src/main/java/org/apache/wiki/api/spi/AclsDSL.java
@@ -0,0 +1,51 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+ */
+package org.apache.wiki.api.spi;
+
+import org.apache.wiki.api.core.Acl;
+import org.apache.wiki.api.core.AclEntry;
+
+
+public class AclsDSL {
+
+    private final AclsSPI aclsSPI;
+
+    AclsDSL( final AclsSPI aclsSPI ) {
+        this.aclsSPI = aclsSPI;
+    }
+
+    /**
+     * Creates a new {@link Acl} instance.
+     *
+     * @return new {@link Acl} instance.
+     */
+    public Acl acl() {
+        return aclsSPI.acl();
+    }
+
+    /**
+     * Creates a new {@link AclEntry} instance.
+     *
+     * @return new {@link AclEntry} instance.
+     */
+    public AclEntry entry() {
+        return aclsSPI.entry();
+    }
+
+}
diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/spi/AclsSPI.java b/jspwiki-api/src/main/java/org/apache/wiki/api/spi/AclsSPI.java
new file mode 100644
index 0000000..ab6fe72
--- /dev/null
+++ b/jspwiki-api/src/main/java/org/apache/wiki/api/spi/AclsSPI.java
@@ -0,0 +1,44 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+ */
+package org.apache.wiki.api.spi;
+
+import org.apache.wiki.api.core.Acl;
+import org.apache.wiki.api.core.AclEntry;
+
+
+/**
+ * SPI used to locate and provide {@link Acl} and {@link AclEntry} instances.
+ */
+public interface AclsSPI {
+
+    /**
+     * Creates a new {@link Acl} instance.
+     *
+     * @return new {@link Acl} instance.
+     */
+    Acl acl();
+
+    /**
+     * Creates a new {@link AclEntry} instance.
+     *
+     * @return new {@link AclEntry} instance.
+     */
+    AclEntry entry();
+
+}
diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/spi/Wiki.java b/jspwiki-api/src/main/java/org/apache/wiki/api/spi/Wiki.java
index 6a5881c..42d8b2f 100644
--- a/jspwiki-api/src/main/java/org/apache/wiki/api/spi/Wiki.java
+++ b/jspwiki-api/src/main/java/org/apache/wiki/api/spi/Wiki.java
@@ -29,10 +29,12 @@
 
 public class Wiki {
 
+    private static final String PROP_PROVIDER_IMPL_ACLS = "jspwiki.provider.impl.acls";
     private static final String PROP_PROVIDER_IMPL_CONTENTS = "jspwiki.provider.impl.contents";
     private static final String PROP_PROVIDER_IMPL_CONTEXT = "jspwiki.provider.impl.context";
     private static final String PROP_PROVIDER_IMPL_ENGINE = "jspwiki.provider.impl.engine";
     private static final String PROP_PROVIDER_IMPL_SESSION = "jspwiki.provider.impl.session";
+    private static final String DEFAULT_PROVIDER_IMPL_ACLS = "org.apache.wiki.spi.AclsSPIDefaultImpl";
     private static final String DEFAULT_PROVIDER_IMPL_CONTENTS = "org.apache.wiki.spi.ContentsSPIDefaultImpl";
     private static final String DEFAULT_PROVIDER_IMPL_CONTEXT = "org.apache.wiki.spi.ContextSPIDefaultImpl";
     private static final String DEFAULT_PROVIDER_IMPL_ENGINE = "org.apache.wiki.spi.EngineSPIDefaultImpl";
@@ -40,6 +42,7 @@
 
     // default values
     private static Properties properties = PropertyReader.getDefaultProperties();
+    private static AclsSPI aclsSPI = getSPI( AclsSPI.class, properties, PROP_PROVIDER_IMPL_ACLS, DEFAULT_PROVIDER_IMPL_ACLS );
     private static ContentsSPI contentsSPI = getSPI( ContentsSPI.class, properties, PROP_PROVIDER_IMPL_CONTENTS, DEFAULT_PROVIDER_IMPL_CONTENTS );
     private static ContextSPI contextSPI = getSPI( ContextSPI.class, properties, PROP_PROVIDER_IMPL_CONTEXT, DEFAULT_PROVIDER_IMPL_CONTEXT );
     private static EngineSPI engineSPI = getSPI( EngineSPI.class, properties, PROP_PROVIDER_IMPL_ENGINE, DEFAULT_PROVIDER_IMPL_ENGINE );
@@ -47,24 +50,54 @@
 
     static void init( final ServletContext context ) {
         properties = PropertyReader.loadWebAppProps( context );
+        aclsSPI = getSPI( AclsSPI.class, properties, PROP_PROVIDER_IMPL_ACLS, DEFAULT_PROVIDER_IMPL_ACLS );
         contentsSPI = getSPI( ContentsSPI.class, properties, PROP_PROVIDER_IMPL_CONTENTS, DEFAULT_PROVIDER_IMPL_CONTENTS );
         contextSPI = getSPI( ContextSPI.class, properties, PROP_PROVIDER_IMPL_CONTEXT, DEFAULT_PROVIDER_IMPL_CONTEXT );
         engineSPI = getSPI( EngineSPI.class, properties, PROP_PROVIDER_IMPL_ENGINE, DEFAULT_PROVIDER_IMPL_ENGINE );
         sessionSPI = getSPI( SessionSPI.class, properties, PROP_PROVIDER_IMPL_SESSION, DEFAULT_PROVIDER_IMPL_SESSION );
     }
 
+    /**
+     * Access to {@link AclsSPI} operations.
+     *
+     * @return {@link AclsSPI} operations.
+     */
+    public static AclsDSL acls() {
+        return new AclsDSL( aclsSPI );
+    }
+
+    /**
+     * Access to {@link ContentsSPI} operations.
+     *
+     * @return {@link ContentsSPI} operations.
+     */
     public static ContentsDSL contents() {
         return new ContentsDSL( contentsSPI );
     }
 
+    /**
+     * Access to {@link ContextSPI} operations.
+     *
+     * @return {@link ContextSPI} operations.
+     */
     public static ContextDSL context() {
         return new ContextDSL( contextSPI );
     }
 
+    /**
+     * Access to {@link EngineSPI} operations.
+     *
+     * @return {@link EngineSPI} operations.
+     */
     public static EngineDSL engine() {
         return new EngineDSL( engineSPI );
     }
 
+    /**
+     * Access to {@link SessionSPI} operations.
+     *
+     * @return {@link SessionSPI} operations.
+     */
     public static SessionDSL session() {
         return new SessionDSL( sessionSPI );
     }
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/WikiPage.java b/jspwiki-main/src/main/java/org/apache/wiki/WikiPage.java
index f278d5b..ce38d23 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/WikiPage.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/WikiPage.java
@@ -203,7 +203,7 @@
      * @return The access control list.  May return null, if there is no acl.
      */
     public Acl getAcl() {
-        return (org.apache.wiki.auth.acl.Acl)m_accessList;
+        return m_accessList;
     }
 
     /**
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/auth/acl/DefaultAclManager.java b/jspwiki-main/src/main/java/org/apache/wiki/auth/acl/DefaultAclManager.java
index e17d807..7279ad0 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/auth/acl/DefaultAclManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/auth/acl/DefaultAclManager.java
@@ -90,7 +90,7 @@
     public Acl parseAcl( final Page page, final String ruleLine ) throws WikiSecurityException {
         Acl acl = page.getAcl();
         if (acl == null) {
-            acl = new AclImpl();
+            acl = Wiki.acls().acl();
         }
 
         try {
@@ -108,7 +108,7 @@
                     oldEntry.addPermission( PermissionFactory.getPagePermission( page, actions ) );
                 } else {
                     log.debug( "Adding new acl entry for " + actions );
-                    final AclEntry entry = new AclEntryImpl();
+                    final AclEntry entry = Wiki.acls().entry();
                     entry.setPrincipal( principal );
                     entry.addPermission( PermissionFactory.getPagePermission( page, actions ) );
 
@@ -148,7 +148,7 @@
                 m_engine.getManager( RenderingManager.class ).getHTML(ctx, page);
 
                 if (page.getAcl() == null) {
-                    page.setAcl( new AclImpl() );
+                    page.setAcl( Wiki.acls().acl() );
                 }
                 acl = page.getAcl();
             }
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java b/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
index 5a213fb..3cade26 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/pages/DefaultPageManager.java
@@ -36,7 +36,6 @@
 import org.apache.wiki.attachment.AttachmentManager;
 import org.apache.wiki.auth.WikiPrincipal;
 import org.apache.wiki.auth.WikiSecurityException;
-import org.apache.wiki.auth.acl.AclEntryImpl;
 import org.apache.wiki.auth.acl.AclManager;
 import org.apache.wiki.auth.user.UserProfile;
 import org.apache.wiki.diff.DifferenceManager;
@@ -746,7 +745,7 @@
                 final AclEntry entry = entries.nextElement();
                 if( ArrayUtils.contains( oldPrincipals, entry.getPrincipal() ) ) {
                     // Create new entry
-                    final AclEntry newEntry = new AclEntryImpl();
+                    final AclEntry newEntry = Wiki.acls().entry();
                     newEntry.setPrincipal( newPrincipal );
                     final Enumeration< Permission > permissions = entry.permissions();
                     while( permissions.hasMoreElements() ) {
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/spi/AclsSPIDefaultImpl.java b/jspwiki-main/src/main/java/org/apache/wiki/spi/AclsSPIDefaultImpl.java
new file mode 100644
index 0000000..91cd311
--- /dev/null
+++ b/jspwiki-main/src/main/java/org/apache/wiki/spi/AclsSPIDefaultImpl.java
@@ -0,0 +1,46 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+ */
+package org.apache.wiki.spi;
+
+import org.apache.wiki.api.core.Acl;
+import org.apache.wiki.api.core.AclEntry;
+import org.apache.wiki.api.spi.AclsSPI;
+import org.apache.wiki.auth.acl.AclEntryImpl;
+import org.apache.wiki.auth.acl.AclImpl;
+
+
+public class AclsSPIDefaultImpl implements AclsSPI {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Acl acl() {
+        return new AclImpl();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public AclEntry entry() {
+        return new AclEntryImpl();
+    }
+
+}
diff --git a/jspwiki-main/src/main/resources/META-INF/services/org.apache.wiki.api.spi.AclsSPI b/jspwiki-main/src/main/resources/META-INF/services/org.apache.wiki.api.spi.AclsSPI
new file mode 100644
index 0000000..212bc21
--- /dev/null
+++ b/jspwiki-main/src/main/resources/META-INF/services/org.apache.wiki.api.spi.AclsSPI
@@ -0,0 +1 @@
+org.apache.wiki.spi.AclsSPIDefaultImpl
\ No newline at end of file
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/auth/acl/AclImplTest.java b/jspwiki-main/src/test/java/org/apache/wiki/auth/acl/AclImplTest.java
index c213463..4907e50 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/auth/acl/AclImplTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/auth/acl/AclImplTest.java
@@ -20,7 +20,10 @@
 
 import org.apache.wiki.TestEngine;
 import org.apache.wiki.WikiSessionTest;
+import org.apache.wiki.api.core.Acl;
+import org.apache.wiki.api.core.AclEntry;
 import org.apache.wiki.api.core.Session;
+import org.apache.wiki.api.spi.Wiki;
 import org.apache.wiki.auth.GroupPrincipal;
 import org.apache.wiki.auth.WikiPrincipal;
 import org.apache.wiki.auth.authorize.Group;
@@ -45,8 +48,8 @@
     final TestEngine engine = TestEngine.build();
     final GroupManager m_groupMgr = engine.getManager( GroupManager.class );
 
-    private AclImpl m_acl;
-    private AclImpl m_aclGroup;
+    private Acl m_acl;
+    private Acl m_aclGroup;
     private Map< String, Group > m_groups;
 
     /**
@@ -57,8 +60,8 @@
     @BeforeEach
     public void setUp() throws Exception {
         final Session m_session = WikiSessionTest.adminSession( engine );
-        m_acl = new AclImpl();
-        m_aclGroup = new AclImpl();
+        m_acl = Wiki.acls().acl();
+        m_aclGroup = Wiki.acls().acl();
         m_groups = new HashMap<>();
         final Principal uAlice = new WikiPrincipal( "Alice" );
         final Principal uBob = new WikiPrincipal( "Bob" );
@@ -66,23 +69,23 @@
         final Principal uDave = new WikiPrincipal( "Dave" );
 
         //  Alice can view
-        final AclEntry ae = new AclEntryImpl();
+        final AclEntry ae = Wiki.acls().entry();
         ae.addPermission( PagePermission.VIEW );
         ae.setPrincipal( uAlice );
 
         //  Charlie can view
-        final AclEntry ae2 = new AclEntryImpl();
+        final AclEntry ae2 = Wiki.acls().entry();
         ae2.addPermission( PagePermission.VIEW );
         ae2.setPrincipal( uCharlie );
 
         //  Bob can view and edit (and by implication, comment)
-        final AclEntry ae3 = new AclEntryImpl();
+        final AclEntry ae3 = Wiki.acls().entry();
         ae3.addPermission( PagePermission.VIEW );
         ae3.addPermission( PagePermission.EDIT );
         ae3.setPrincipal( uBob );
 
         // Dave can view and comment
-        final AclEntry ae4 = new AclEntryImpl();
+        final AclEntry ae4 = Wiki.acls().entry();
         ae4.addPermission( PagePermission.VIEW );
         ae4.addPermission( PagePermission.COMMENT );
         ae4.setPrincipal( uDave );
@@ -98,7 +101,7 @@
         m_groupMgr.setGroup( m_session, foo );
         foo.add( uAlice );
         foo.add( uBob );
-        final AclEntry ag1 = new AclEntryImpl();
+        final AclEntry ag1 = Wiki.acls().entry();
         ag1.setPrincipal( foo.getPrincipal() );
         ag1.addPermission( PagePermission.EDIT );
         m_aclGroup.addEntry( ag1 );
@@ -109,7 +112,7 @@
         m_groupMgr.setGroup( m_session, bar );
         bar.add( uBob );
         bar.add( uCharlie );
-        final AclEntry ag2 = new AclEntryImpl();
+        final AclEntry ag2 = Wiki.acls().entry();
         ag2.setPrincipal( bar.getPrincipal() );
         ag2.addPermission( PagePermission.VIEW );
         m_aclGroup.addEntry( ag2 );
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/auth/acl/DefaultAclManagerTest.java b/jspwiki-main/src/test/java/org/apache/wiki/auth/acl/DefaultAclManagerTest.java
index 37323ba..a6ce034 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/auth/acl/DefaultAclManagerTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/auth/acl/DefaultAclManagerTest.java
@@ -24,6 +24,7 @@
 import org.apache.wiki.api.core.AclEntry;
 import org.apache.wiki.api.core.Page;
 import org.apache.wiki.api.exceptions.ProviderException;
+import org.apache.wiki.api.spi.Wiki;
 import org.apache.wiki.auth.WikiPrincipal;
 import org.apache.wiki.auth.permissions.PermissionFactory;
 import org.apache.wiki.pages.PageManager;
@@ -169,13 +170,13 @@
         Assertions.assertEquals( "[{ALLOW edit Charlie,Herman}]\n", aclString );
 
         // Create an ACL from scratch
-        acl = new AclImpl();
-        AclEntry entry = new AclEntryImpl();
+        acl = Wiki.acls().acl();
+        AclEntry entry = Wiki.acls().entry();
         entry.setPrincipal( new WikiPrincipal( "Charlie" ) );
         entry.addPermission( PermissionFactory.getPagePermission( "Main:Foo", "view" ) );
         entry.addPermission( PermissionFactory.getPagePermission( "Main:Foo", "edit" ) );
         acl.addEntry( entry );
-        entry = new AclEntryImpl();
+        entry = Wiki.acls().entry();
         entry.setPrincipal( new WikiPrincipal( "Devin" ) );
         entry.addPermission( PermissionFactory.getPagePermission( "Main:Foo", "edit" ) );
         entry.addPermission( PermissionFactory.getPagePermission( "Main:Foo", "delete" ) );