Merged enterprise features

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2746 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Paul Holmes-Higgin
2006-05-03 18:34:13 +00:00
parent 405c00bd8e
commit c37ff8805c
83 changed files with 15809 additions and 9 deletions

View File

@@ -7,12 +7,12 @@
<!-- --> <!-- -->
<!-- This implementation supports the identification of users as admin users. --> <!-- This implementation supports the identification of users as admin users. -->
<!-- It does NOT support any other groupings of users. --> <!-- It also supports groups and allows groups and users to be arranged into -->
<!-- hierarchies. -->
<!-- --> <!-- -->
<beans> <beans>
<bean id="authorityService" class="org.alfresco.repo.security.authority.SimpleAuthorityServiceImpl">
<!-- Wiring up of services on which this service depends --> <bean id="authorityService" class="org.alfresco.repo.security.authority.AuthorityServiceImpl">
<property name="authenticationComponent"> <property name="authenticationComponent">
<ref bean="authenticationComponent" /> <ref bean="authenticationComponent" />
</property> </property>
@@ -22,6 +22,12 @@
<property name="nodeService"> <property name="nodeService">
<ref bean="nodeService" /> <ref bean="nodeService" />
</property> </property>
<property name="authorityDAO">
<ref bean="authorityDAO" />
</property>
<property name="permissionServiceSPI">
<ref bean="permissionServiceImpl" />
</property>
<!-- --> <!-- -->
<!-- A list of users with admin rights. --> <!-- A list of users with admin rights. -->
<!-- --> <!-- -->
@@ -42,4 +48,28 @@
</set> </set>
</property> </property>
</bean> </bean>
<!-- Authority DAO that stores group information along with user information, -->
<!-- in the repository. -->
<!-- -->
<!-- This bean uses the userToAuthorityCache configured in cache-context.xml -->
<!-- -->
<bean id="authorityDAO" class="org.alfresco.repo.security.authority.AuthorityDAOImpl">
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="namespacePrefixResolver">
<ref bean="namespaceService" />
</property>
<property name="searchService">
<ref bean="searchService" />
</property>
<property name="dictionaryService">
<ref bean="dictionaryService" />
</property>
<property name="userToAuthorityCache">
<ref bean="userToAuthorityCache" />
</property>
</bean>
</beans> </beans>

Binary file not shown.

View File

@@ -0,0 +1,93 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<!-- Chaining -->
<bean id="authenticationServiceImpl" class="org.alfresco.repo.security.authentication.ChainingAuthenticationServiceImpl">
<property name="authenticationServices">
<list>
<ref bean="authenticationServiceImplJAAS"/>
</list>
</property>
<property name="mutableAuthenticationService">
<ref bean="authenticationServiceImplAlfresco"/>
</property>
</bean>
<!-- Alfresco Auth -->
<bean id="authenticationServiceImplAlfresco" class="org.alfresco.repo.security.authentication.AuthenticationServiceImpl">
<property name="authenticationDao">
<ref bean="authenticationDaoAlfresco"/>
</property>
<property name="ticketComponent">
<ref bean="ticketComponent"/>
</property>
<property name="authenticationComponent">
<ref bean="authenticationComponentImplAlfresco"/>
</property>
</bean>
<bean id="authenticationDaoAlfresco" class="org.alfresco.repo.security.authentication.RepositoryAuthenticationDao">
<property name="nodeService">
<ref bean="nodeService"/>
</property>
<property name="dictionaryService">
<ref bean="dictionaryService"/>
</property>
<property name="namespaceService">
<ref bean="namespaceService"/>
</property>
<property name="searchService">
<ref bean="searchService"/>
</property>
<property name="userNamesAreCaseSensitive">
<value>${user.name.caseSensitive}</value>
</property>
<property name="passwordEncoder">
<ref bean="passwordEncoder"/>
</property>
</bean>
<bean id="authenticationComponentImplAlfresco" class="org.alfresco.repo.security.authentication.AuthenticationComponentImpl">
<property name="authenticationDao">
<ref bean="authenticationDaoAlfresco"/>
</property>
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="allowGuestLogin">
<value>true</value>
</property>
</bean>
<!-- JAAS -->
<bean id="authenticationServiceImplJAAS" class="org.alfresco.repo.security.authentication.AuthenticationServiceImpl">
<property name="authenticationDao">
<ref bean="authenticationDaoJAAS"/>
</property>
<property name="ticketComponent">
<ref bean="ticketComponent"/>
</property>
<property name="authenticationComponent">
<ref bean="authenticationComponentImplJAAS"/>
</property>
</bean>
<bean id="authenticationComponentImplJAAS" class="org.alfresco.repo.security.authentication.jaas.JAASAuthenticationComponent">
<property name="realm">
<value>COMPANY.COM</value>
</property>
<property name="jaasConfigEntryName">
<value>Alfresco</value>
</property>
</bean>
<bean id="authenticationDaoJAAS" class="org.alfresco.repo.security.authentication.ntlm.NullMutableAuthenticationDao"/>
</beans>

View File

@@ -0,0 +1,38 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<!-- The authentication component. -->
<!-- Jass authentication - most of the config goes somewhere else -->
<bean id="authenticationComponentImpl"
class="org.alfresco.repo.security.authentication.jaas.JAASAuthenticationComponent">
<property name="realm">
<value>DEFAULT.REALM</value>
</property>
<property name="jaasConfigEntryName">
<value>Alfresco</value>
</property>
</bean>
<bean id="alfDaoImpl" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces">
<value>
org.alfresco.repo.security.authentication.MutableAuthenticationDao
</value>
</property>
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<bean class="org.alfresco.repo.security.authentication.ntlm.NullMutableAuthenticationDao" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">${server.transaction.mode.default}</prop>
</props>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,442 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<!-- DAO that rejects changes - LDAP is read only at the moment -->
<bean id="alfDaoImpl" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.alfresco.repo.security.authentication.MutableAuthenticationDao</value>
</property>
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<bean class="org.alfresco.repo.security.authentication.ntlm.NullMutableAuthenticationDao" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">${server.transaction.mode.default}</prop>
</props>
</property>
</bean>
<!-- LDAP authentication configuration -->
<!--
You can also use JAAS authentication for Kerberos against Active Directory or NTLM if you also require single sign on from the
web browser. You do not have to use LDAP authentication to synchronise groups and users from an LDAP store if it supports other
authentication routes, like Active Directory.
-->
<bean id="authenticationComponentImpl" class="org.alfresco.repo.security.authentication.ldap.LDAPAuthenticationComponentImpl">
<property name="LDAPInitialDirContextFactory">
<ref bean="ldapInitialDirContextFactory"/>
</property>
<property name="userNameFormat">
<!--
This maps between what the user types in and what is passed through to the underlying LDAP authentication.
"%s" - the user id is passed through without modification.
Used for LDAP authentication such as DIGEST-MD5, anything that is not "simple".
"cn=%s,ou=London,dc=company,dc=com" - If the user types in "Joe Bloggs" the authentricate as "cn=Joe Bloggs,ou=London,dc=company,dc=com"
Usually for simple authentication.
-->
<value>%s</value>
</property>
</bean>
<!--
This bean is used to support general LDAP authentication. It is also used to provide read only access to users and groups
to pull them out of the LDAP reopsitory
-->
<bean id="ldapInitialDirContextFactory" class="org.alfresco.repo.security.authentication.ldap.LDAPInitialDirContextFactoryImpl">
<property name="initialDirContextEnvironment">
<map>
<!-- The LDAP provider -->
<entry key="java.naming.factory.initial">
<value>com.sun.jndi.ldap.LdapCtxFactory</value>
</entry>
<!-- The url to the LDAP server -->
<!-- Note you can use space separated urls - they will be tried in turn until one works -->
<!-- This could be used to authenticate against one or more ldap servers (you will not know which one ....) -->
<entry key="java.naming.provider.url">
<value>ldap://openldap.domain.com:389</value>
</entry>
<!-- The authentication mechanism to use -->
<!-- Some sasl authentication mechanisms may require a realm to be set -->
<!-- java.naming.security.sasl.realm -->
<!-- The available options will depend on your LDAP provider -->
<entry key="java.naming.security.authentication">
<value>DIGEST-MD5</value>
</entry>
<!-- The id of a user who can read group and user information -->
<!-- This does not go through the pattern substitution defined above and is used "as is" -->
<entry key="java.naming.security.principal">
<value>reader</value>
</entry>
<!-- The password for the user defined above -->
<entry key="java.naming.security.credentials">
<value>secret</value>
</entry>
</map>
</property>
</bean>
<!-- Ldap Syncronisation support -->
<!--
There can be more than one stack of beans that import users or groups. For example, it may be easier
to have a version of ldapPeopleExportSource, and associated beans, for each sub-tree of your ldap directory
from which you want to import users. You could then limit users to be imported from two or more sub tress and ignore
users found else where. The same applies to the import of groups.
The defaults shown below are for OpenLDAP.
-->
<!-- Extract user information from LDAP and transform this to XML -->
<bean id="ldapPeopleExportSource" class="org.alfresco.repo.security.authentication.ldap.LDAPPersonExportSource">
<!--
The query to select objects that represent the users to import.
For Open LDAP, using a basic schema, the following is probably what you want:
(objectclass=inetOrgPerson)
For Active Directory:
(objectclass=user)
-->
<property name="personQuery">
<value>(objectclass=inetOrgPerson)</value>
</property>
<!--
The seach base restricts the LDAP query to a sub section of tree on the LDAP server.
-->
<property name="searchBase">
<value>dc=alfresco,dc=org</value>
</property>
<!--
The unique identifier for the user.
THIS MUST MATCH WHAT THE USER TYPES IN AT THE LOGIN PROMPT
For simple LDAP authentication this is likely to be "cn" or, less friendly, "distinguishedName"
In OpenLDAP, using other authentication mechanisms "uid", but this depends on how you map
from the id in the LDAP authentication request to search for the inetOrgPerson against which
to authenticate.
In Active Directory this is most likely to be "sAMAccountName"
This property is mandatory and must appear on all users found by the query defined above.
-->
<property name="userIdAttributeName">
<value>uid</value>
</property>
<!-- Services -->
<property name="LDAPInitialDirContextFactory">
<ref bean="ldapInitialDirContextFactory"/>
</property>
<property name="personService">
<ref bean="personService"></ref>
</property>
<property name="namespaceService">
<ref bean="namespaceService"/>
</property>
<!--
The path to the location of a space to use as the default home folder.
This folder should be readable by all users, or a group to which all imported users belong.
-->
<property name="defaultHomeFolder">
<value>/app:company_home</value>
</property>
<!--
This property defines a mapping between attributes held on LDAP user objects and
the properties of user objects held in the repository. The key is the QName of an attribute in
the repository, the value is the attribute name from the user/inetOrgPerson/.. object in the
LDAP repository.
-->
<property name="attributeMapping">
<map>
<entry key="cm:userName">
<!-- Must match the same attribute as userIdAttributeName -->
<value>uid</value>
</entry>
<entry key="cm:firstName">
<!-- OpenLDAP: "givenName" -->
<!-- Active Directory: "givenName" -->
<value>givenName</value>
</entry>
<entry key="cm:lastName">
<!-- OpenLDAP: "sn" -->
<!-- Active Directory: "sn" -->
<value>sn</value>
</entry>
<entry key="cm:email">
<!-- OpenLDAP: "mail" -->
<!-- Active Directory: "???" -->
<value>mail</value>
</entry>
<entry key="cm:organizationId">
<!-- OpenLDAP: "o" -->
<!-- Active Directory: "???" -->
<value>o</value>
</entry>
</map>
</property>
</bean>
<!-- Extract group information from LDAP and transform this to XML -->
<bean id="ldapGroupExportSource" class="org.alfresco.repo.security.authentication.ldap.LDAPGroupExportSource">
<!--
The query to select objects that represent the groups to import.
For Open LDAP, using a basic schema, the following is probably what you want:
(objectclass=groupOfNames)
For Active Directory:
(objectclass=group)
-->
<property name="groupQuery">
<value>(objectclass=groupOfNames)</value>
</property>
<!--
The seach base restricts the LDAP query to a sub section of tree on the LDAP server.
-->
<property name="searchBase">
<value>dc=alfresco,dc=org</value>
</property>
<!--
The unique identifier for the user. This must match the userIdAttributeName on the ldapPeopleExportSource bean above.
-->
<property name="userIdAttributeName">
<value>uid</value>
</property>
<!--
An attribute that is a unique identifier for each group found.
This is also the name of the group with the current group implementation.
This is mandatory for any groups found.
OpenLDAP: "cn" as it is mandatory on groupOfNames
Active Directory: "cn"
-->
<property name="groupIdAttributeName">
<value>cn</value>
</property>
<!--
The objectClass attribute for group members.
For each member of a group, the distinguished name is given.
The object is looked up by its DN. If the object is of this class it is treated as a group.
-->
<property name="groupType">
<value>groupOfNames</value>
</property>
<!--
The objectClass attribute for person members.
For each member of a group, the distinguished name is given.
The object is looked up by its DN. If the object is of this class it is treated as a person.
-->
<property name="personType">
<value>inetOrgPerson</value>
</property>
<property name="LDAPInitialDirContextFactory">
<ref bean="ldapInitialDirContextFactory"/>
</property>
<property name="namespaceService">
<ref bean="namespaceService"/>
</property>
<!--
The repeating attribute on group objects (found by query or as sub groups)
used to define membership of the group. This is assumed to hold distinguished names of
other groups or users/people; the above types are used to determine this.
OpenLDAP: "member" as it is mandatory on groupOfNames
Active Directory: "member"
-->
<property name="memberAttribute">
<value>member</value>
</property>
</bean>
<!-- Job definitions to import LDAP people and groups -->
<!-- The triggers register themselves with the scheduler -->
<!-- You may comment in the default scheduler to enable these triggers -->
<!-- If a cron base trigger is what you want seee scheduled-jobs-context.xml for examples. -->
<!-- Trigger to load poeple -->
<!-- Note you can have more than one initial (context, trigger, import job and export source) set -->
<!-- This would allow you to load people from more than one ldap store -->
<bean id="ldapPeopleTrigger" class="org.alfresco.util.TriggerBean">
<property name="jobDetail">
<bean id="ldapPeopleJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>org.alfresco.repo.importer.ImporterJob</value>
</property>
<property name="jobDataAsMap">
<map>
<entry key="bean">
<ref bean="ldapPeopleImport"/>
</entry>
</map>
</property>
</bean>
</property>
<!-- Start after 30 seconds of starting the repository -->
<property name="startDelay">
<value>30000</value>
</property>
<!-- Repeat every hour -->
<property name="repeatInterval">
<value>3600000</value>
</property>
<!-- Commented out to disable
<property name="scheduler">
<ref bean="schedulerFactory" />
</property>
-->
</bean>
<bean id="ldapGroupTrigger" class="org.alfresco.util.TriggerBean">
<property name="jobDetail">
<bean id="ldapGroupJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>org.alfresco.repo.importer.ImporterJob</value>
</property>
<property name="jobDataAsMap">
<map>
<entry key="bean">
<ref bean="ldapGroupImport"/>
</entry>
</map>
</property>
</bean>
</property>
<!-- Start after 30 seconds of starting the repository -->
<property name="startDelay">
<value>30000</value>
</property>
<!-- Repeat every hour -->
<property name="repeatInterval">
<value>3600000</value>
</property>
<!-- Commented out to disable
<property name="scheduler">
<ref bean="schedulerFactory" />
</property>
-->
</bean>
<!-- The bean that imports xml describing people -->
<bean id="ldapPeopleImport" class="org.alfresco.repo.importer.ExportSourceImporter">
<property name="importerService">
<ref bean="importerComponent"/>
</property>
<property name="transactionService">
<ref bean="transactionComponent"/>
</property>
<property name="authenticationComponent">
<ref bean="authenticationComponent"/>
</property>
<property name="exportSource">
<ref bean="ldapPeopleExportSource"/>
</property>
<!-- The store that contains people - this should not be changed -->
<property name="storeRef">
<value>${spaces.store}</value>
</property>
<!-- The location of people nodes within the store defined above - this should not be changed -->
<property name="path">
<value>/${system.system_container.childname}/${system.people_container.childname}</value>
</property>
<!-- If true, clear all existing people before import, if false update/add people from the xml -->
<property name="clearAllChildren">
<value>false</value>
</property>
<property name="nodeService">
<ref bean="nodeService"/>
</property>
<property name="searchService">
<ref bean="searchService"/>
</property>
<property name="namespacePrefixResolver">
<ref bean="namespaceService"/>
</property>
</bean>
<!-- The bean that imports xml descibing groups -->
<bean id="ldapGroupImport" class="org.alfresco.repo.importer.ExportSourceImporter">
<property name="importerService">
<ref bean="importerComponent"/>
</property>
<property name="transactionService">
<ref bean="transactionComponent"/>
</property>
<property name="authenticationComponent">
<ref bean="authenticationComponent"/>
</property>
<property name="exportSource">
<ref bean="ldapGroupExportSource"/>
</property>
<!-- The store that contains group information - this should not be changed -->
<property name="storeRef">
<value>${alfresco_user_store.store}</value>
</property>
<!-- The location of group information in the store above - this should not be changed -->
<property name="path">
<value>/${alfresco_user_store.system_container.childname}/${alfresco_user_store.authorities_container.childname}</value>
</property>
<!-- If true, clear all existing groups before import, if false update/add groups from the xml -->
<property name="clearAllChildren">
<value>true</value>
</property>
<property name="nodeService">
<ref bean="nodeService"/>
</property>
<property name="searchService">
<ref bean="searchService"/>
</property>
<property name="namespacePrefixResolver">
<ref bean="namespaceService"/>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,35 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean id="authenticationDao" class="org.alfresco.repo.security.authentication.ntlm.NullMutableAuthenticationDao" />
<!-- The authentication component. -->
<!-- Use the passthru authentication component to authenticate using -->
<!-- user accounts on one or more Windows servers. -->
<!-- Properties that specify the server(s) to use for passthru -->
<!-- authentication :- -->
<!-- useLocalServer use the local server for authentication -->
<!-- domain use domain controllers from the specified domain-->
<!-- servers comma delimted list of server addresses or -->
<!-- names -->
<bean id="authenticationComponentImpl" class="org.alfresco.repo.security.authentication.ntlm.NTLMAuthenticationComponentImpl">
<property name="useLocalServer">
<value>true</value>
</property>
<property name="personService">
<ref bean="personService" />
</property>
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="guestAccess">
<value>false</value>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,71 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<!--
This file is not included in the application context by default.
If you include this file, please ensure that you review the sample
beans contained here.
-->
<bean id="backupContentStore"
class="org.alfresco.repo.content.filestore.FileContentStore">
<constructor-arg>
<value>s:/backups/alfresco</value>
</constructor-arg>
</bean>
<bean id="primaryContentStoreBackupComponent"
class="org.alfresco.repo.content.replication.ContentStoreReplicator"
depends-on="fileContentStore, backupContentStore"
init-method="start">
<!-- content source -->
<property name="sourceStore">
<value>fileContentStore</value>
</property>
<!-- content target -->
<property name="targetStore">
<value>backupContentStore</value>
</property>
<!-- set to 'false' to perform a single pass before quitting -->
<property name="runContinuously">
<value>true</value>
</property>
<!-- time between passes -->
<property name="waitTime">
<value>60</value>
</property>
</bean>
<bean id="replicatingContentStore"
class="org.alfresco.repo.content.replication.ReplicatingContentStore" >
<!-- the preferred store for reads and writes -->
<property name="primaryStore">
<ref bean="fileContentStore" />
</property>
<!-- example of possible secondary store configuration -->
<property name="secondaryStores">
<list>
<ref bean="archiveStoreA" />
<ref bean="archiveStoreB" />
</list>
</property>
<!-- enable content missing from the primary store to be pulled in from the secondary stores -->
<property name="inbound">
<value>false</value>
</property>
<!-- enable replication from the primary to the secondary stores -->
<property name="outbound">
<value>false</value>
</property>
<!-- this is required if outbound replication is active, otherwise not -->
<property name="transactionService">
<ref bean="transactionComponent" />
</property>
<!-- set this to force outbound replication to be asynchronous -->
<property name="outboundThreadPoolExecutor">
<ref bean="threadPoolExecutor" />
</property>
</bean>
</beans>

View File

@@ -3,22 +3,48 @@
<beans> <beans>
<!-- full node index recovery --> <bean id="indexRecoveryComponentBase" abstract="true" >
<bean id="indexRecoveryComponent" class="org.alfresco.repo.node.index.FtsIndexRecoveryComponent" > <property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
<property name="transactionService"> <property name="transactionService">
<ref bean="transactionComponent" /> <ref bean="transactionComponent" />
</property> </property>
<property name="indexer">
<ref bean="indexerComponent" />
</property>
<property name="ftsIndexer"> <property name="ftsIndexer">
<ref bean="LuceneFullTextSearchIndexer" /> <ref bean="LuceneFullTextSearchIndexer" />
</property> </property>
<property name="searcher">
<ref bean="searchService" />
</property>
<property name="nodeService"> <property name="nodeService">
<ref bean="nodeService" /> <ref bean="nodeService" />
</property> </property>
<property name="stores"> <property name="stores">
<list> <list>
<value>workspace://SpacesStore</value> <value>workspace://SpacesStore</value>
<value>workspace://lightWeightVersionStore</value>
<value>user://alfrescoUserStore</value>
</list> </list>
</property> </property>
</bean> </bean>
<!-- full node index recovery -->
<bean id="indexRecoveryComponent" class="org.alfresco.repo.node.index.FullIndexRecoveryComponent" parent="indexRecoveryComponentBase">
<property name="executeFullRecovery">
<value>false</value> <!-- enable this to start the full index recovery -->
</property>
<property name="runContinuously">
<value>false</value> <!-- ensure the index is up to date and then stop -->
</property>
<property name="waitTime">
<value>1000</value> <!-- milliseconds to wait between checks for new transactions -->
</property>
<property name="l2CacheMode">
<value>NORMAL</value> <!-- normal L2 cache usage (database is changed by this server only) -->
</property>
</bean>
</beans> </beans>

View File

@@ -7,7 +7,7 @@
version.major=1 version.major=1
version.minor=3 version.minor=3
version.revision=0 version.revision=0
version.label= version.label=dev
# Edition label # Edition label

Binary file not shown.

View File

@@ -0,0 +1,513 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "stdafx.h"
#include "CAlfrescoApp.h"
#include "CAlfrescoAppDlg.h"
#include "FileStatusDialog.h"
#include <stdlib.h>
#include "util\String.h"
#include "util\DataBuffer.h"
#include "util\FileName.h"
#include <shellapi.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
using namespace std;
using namespace Alfresco;
// CCAlfrescoAppApp
BEGIN_MESSAGE_MAP(CCAlfrescoAppApp, CWinApp)
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
// CCAlfrescoAppApp construction
CCAlfrescoAppApp::CCAlfrescoAppApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CCAlfrescoAppApp object
CCAlfrescoAppApp theApp;
// CCAlfrescoAppApp initialization
BOOL CCAlfrescoAppApp::InitInstance()
{
// InitCommonControls() is required on Windows XP if an application
// manifest specifies use of ComCtl32.dll version 6 or later to enable
// visual styles. Otherwise, any window creation will fail.
InitCommonControls();
CWinApp::InitInstance();
AfxEnableControlContainer();
// Get the application path
String appPath = __wargv[0];
int pos = appPath.lastIndexOf(PathSeperator);
if ( pos < 0) {
AfxMessageBox( L"Invalid application path", MB_OK | MB_ICONSTOP);
return 1;
}
// Get the path to the folder containing the application
String folderPath = appPath.substring(0, pos);
// Create the Alfresco interface
AlfrescoInterface alfresco(folderPath);
if ( alfresco.isAlfrescoFolder()) {
try {
// If there are no file paths on the command line then display a status page for the files
// in the Alfresco folder
if ( __argc == 1) {
// Display status for the files in the Alfresco folder
doFolderStatus( alfresco);
}
else {
// Build a list of the file names
StringList fileList;
for ( int i = 1; i < __argc; i++)
fileList.addString( String(__wargv[i]));
// Process the file list and check in or out each file
doCheckInOut( alfresco, fileList);
}
}
catch (Exception ex) {
CString msg;
msg.FormatMessage( L"Exception occurred\n\n%1", ex.getMessage().data());
AfxMessageBox( msg, MB_OK | MB_ICONSTOP);
}
}
else {
AfxMessageBox( L"Not a valid Alfresco CIFS folder", MB_OK | MB_ICONSTOP);
return 1;
}
// Run the main dialog
/**
CCAlfrescoAppDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
**/
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
/**
* Display file status of the files in the target Alfresco folder
*
* @param AlfrescoInterface& alfresco
* @param const wchar_t* fileSpec
* @return bool
*/
bool CCAlfrescoAppApp::doFolderStatus( AlfrescoInterface& alfresco, const wchar_t* fileSpec) {
// Get the base UNC path
String uncPath = alfresco.getUNCPath();
uncPath.append(PathSeperator);
// Search the Alfresco folder
WIN32_FIND_DATA findData;
String searchPath = uncPath;
searchPath.append( fileSpec);
bool sts = false;
HANDLE fHandle = FindFirstFile( searchPath, &findData);
AlfrescoFileInfoList fileList;
if ( fHandle != INVALID_HANDLE_VALUE) {
// Loop until all files have been returned
PTR_AlfrescoFileInfo pFileInfo;
sts = true;
while ( fHandle != INVALID_HANDLE_VALUE) {
// Get the file name, ignore the '.' and '..' files
String fName = findData.cFileName;
if ( fName.equals(L".") || fName.equals(L"..")) {
// Get the next file/folder name in the search
if ( FindNextFile( fHandle, &findData) == 0)
fHandle = INVALID_HANDLE_VALUE;
continue;
}
// Get the file information for the current file folder
pFileInfo = alfresco.getFileInformation( findData.cFileName);
if ( pFileInfo.get() != NULL) {
// Add the file to the list
fileList.addInfo( pFileInfo);
}
// Get the next file/folder name in the search
if ( FindNextFile( fHandle, &findData) == 0)
fHandle = INVALID_HANDLE_VALUE;
}
}
// Display the file status dialog if there are files to display
if ( fileList.size() > 0) {
// Display the file status dialog
CFileStatusDialog dlg( fileList);
dlg.DoModal();
}
else {
CString msg;
msg.FormatMessage( L"No files found in %1", uncPath.data());
AfxMessageBox( msg, MB_OK | MB_ICONINFORMATION);
}
// Return status
return sts;
}
/**
* Process the list of files and check in or out each file
*
* @param alfresco AlfrescoInterface&
* @param files StringList&
*/
bool CCAlfrescoAppApp::doCheckInOut( AlfrescoInterface& alfresco, StringList& files) {
// Process the list of files and either check in the file if it is a working copy or check out
// the file
for ( unsigned int i = 0; i < files.numberOfStrings(); i++) {
// Get the current file name
String curFile = files.getStringAt( i);
// Check if the path is on an Alfresco mapped drive
if ( alfresco.isMappedDrive() && curFile.startsWithIgnoreCase( alfresco.getDrivePath())) {
// Convert the path to a UNC path
String uncPath = alfresco.getRootPath();
uncPath.append( curFile.substring(2));
curFile = uncPath;
}
// Check that the path is to a file
bool copyFile = false;
DWORD attr = GetFileAttributes( curFile);
if ( attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
// Get the file name from the path
StringList nameParts = FileName::splitPath( curFile);
String curName = nameParts.getStringAt( 1);
// Get the Alfresco file status information
PTR_AlfrescoFileInfo pFileInfo = alfresco.getFileInformation( curName);
// If the path is to a file that is not on the Alfresco share the file will need to be copied,
// after checking the status of a matching file in the Alfresco folder
if ( curFile.length() >= 3 && curFile.substring(1,3).equals( L":\\")) {
// Check if there is an existing file with the same name
if ( pFileInfo.get() != NULL) {
// Check if the file is a working copy
if ( pFileInfo->isWorkingCopy()) {
// Local file matches a working copy file in the Alfresco folder
CString msg;
msg.FormatMessage( L"Found matching working copy for local file %1", curName.data());
AfxMessageBox( msg, MB_OK | MB_ICONINFORMATION);
}
else if ( pFileInfo->getLockType() != LockNone) {
// File is locked, may be the original document
CString msg;
msg.FormatMessage( L"Destination file %1 is locked", curName.data());
AfxMessageBox( msg, MB_OK | MB_ICONSTOP);
return false;
}
else {
// Indicate that we have copied a new file to the Alfresco share, do not check in/out
copyFile = true;
}
}
else {
// Indicate that we have copied a new file to the Alfresco share, do not check in/out
copyFile = true;
}
// Build the from/to paths, must be double null terminated
wchar_t fromPath[MAX_PATH + 1];
wchar_t toPath[MAX_PATH + 1];
memset( fromPath, 0, sizeof( fromPath));
memset( toPath, 0, sizeof( toPath));
wcscpy( fromPath, curFile.data());
wcscpy( toPath, alfresco.getUNCPath());
// Copy the local file to the Alfresco folder
SHFILEOPSTRUCT fileOpStruct;
memset( &fileOpStruct, 0, sizeof(SHFILEOPSTRUCT));
fileOpStruct.hwnd = HWND_DESKTOP;
fileOpStruct.wFunc = FO_COPY;
fileOpStruct.pFrom = fromPath;
fileOpStruct.pTo = toPath;
fileOpStruct.fFlags= 0;
fileOpStruct.fAnyOperationsAborted =false;
// Copy the file to the Alfresco folder
if ( SHFileOperation( &fileOpStruct) != 0) {
// File copy failed
CString msg;
msg.FormatMessage( L"Failed to copy file %1", curFile.data());
AfxMessageBox( msg, MB_OK | MB_ICONSTOP);
return false;
}
else if ( fileOpStruct.fAnyOperationsAborted) {
// User aborted the file copy
CString msg;
msg.FormatMessage( L"Copy aborted for %1", curFile.data());
AfxMessageBox( msg, MB_OK | MB_ICONSTOP);
return false;
}
// Get the file information for the copied file
pFileInfo = alfresco.getFileInformation( curName);
}
// Check in or check out the file
if ( pFileInfo.get() != NULL) {
// Check if the file should be checked in/out
if ( copyFile == false) {
// Check if the file is a working copy, if so then check it in
if ( pFileInfo->isWorkingCopy()) {
// Check in the file
doCheckIn( alfresco, pFileInfo);
}
else if ( pFileInfo->getLockType() == LockNone) {
// Check out the file
doCheckOut( alfresco, pFileInfo);
}
else {
// File is locked, may already be checked out
CString msg;
msg.FormatMessage( L"File %1 is locked", curFile.data());
AfxMessageBox( msg, MB_OK | MB_ICONSTOP);
}
}
else {
// No existing file to link the copied file to
CString msg;
msg.FormatMessage( L"Copied file %1 to Alfresco folder", curFile.data());
AfxMessageBox( msg, MB_OK | MB_ICONINFORMATION);
}
}
else {
CString msg;
msg.FormatMessage( L"Failed to get file status for %1", curFile.data());
AfxMessageBox( msg, MB_OK | MB_ICONSTOP);
}
}
else {
// Check the error status
CString msg;
if ( attr != INVALID_FILE_ATTRIBUTES)
msg.FormatMessage( L"Path %1 is a folder, ignored", curFile.data());
else
msg.FormatMessage( L"File %1 does not exist", curFile.data());
AfxMessageBox( msg, MB_OK | MB_ICONSTOP);
}
}
// Return status
return true;
}
/**
* Check in the specified file
*
* @param alfresco AlfrescoInterface&
* @param pFileInfo PTR_AlfrescoFileInfo&
* @return bool
*/
bool CCAlfrescoAppApp::doCheckIn( AlfrescoInterface& alfresco, PTR_AlfrescoFileInfo& pFileInfo) {
bool checkedIn = false;
try {
// Check in the specified file
alfresco.checkIn( pFileInfo->getName());
CString msg;
msg.FormatMessage( L"Checked in file %1", pFileInfo->getName().data());
AfxMessageBox( msg, MB_OK | MB_ICONINFORMATION);
// Indicate that the check in was successful
checkedIn = true;
}
catch (Exception ex) {
CString msg;
msg.FormatMessage( L"Error checking in file %1\n\n%2", pFileInfo->getName().data(), ex.getMessage().data());
AfxMessageBox( msg, MB_OK | MB_ICONSTOP);
}
// Return the check in status
return checkedIn;
}
/**
* Check out the specified file
*
* @param alfresco AlfrescoInterface&
* @param pFileInfo PTR_AlfrescoFileInfo&
* @return bool
*/
bool CCAlfrescoAppApp::doCheckOut( AlfrescoInterface& alfresco, PTR_AlfrescoFileInfo& pFileInfo) {
bool checkedOut = false;
try {
// Check out the specified file
String workingCopy;
alfresco.checkOut( pFileInfo->getName(), workingCopy);
CString msg;
msg.FormatMessage( L"Checked out file %1 to %2", pFileInfo->getName().data(), workingCopy.data());
AfxMessageBox( msg, MB_OK | MB_ICONINFORMATION);
// Indicate that the check out was successful
checkedOut = true;
}
catch (Exception ex) {
CString msg;
msg.FormatMessage( L"Error checking out file %1\n\n%2", pFileInfo->getName().data(), ex.getMessage().data());
AfxMessageBox( msg, MB_OK | MB_ICONSTOP);
}
// Return the check out status
return checkedOut;
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#pragma once
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
// Includes
#include "alfresco\Alfresco.hpp"
using namespace Alfresco;
// CCAlfrescoAppApp:
// See CAlfrescoApp.cpp for the implementation of this class
//
class CCAlfrescoAppApp : public CWinApp
{
public:
CCAlfrescoAppApp();
// Overrides
public:
virtual BOOL InitInstance();
// Implementation
DECLARE_MESSAGE_MAP()
private:
// Main Alfresco interface functions
bool doFolderStatus( AlfrescoInterface& alfresco, const wchar_t* fileSpec = L"*.*");
bool doCheckInOut( AlfrescoInterface& alfresco, StringList& files);
bool doCheckIn( AlfrescoInterface& alfresco, PTR_AlfrescoFileInfo& fileInfo);
bool doCheckOut( AlfrescoInterface& alfresco, PTR_AlfrescoFileInfo& fileInfo);
};
extern CCAlfrescoAppApp theApp;

View File

@@ -0,0 +1,19 @@
<HTML>
<BODY ID=CCAlfrescoAppDlg BGCOLOR=LIGHTGREY>
<TABLE WIDTH=100%>
<TR>
<TD ALIGN=RIGHT>
<BUTTON STYLE="WIDTH:100" ID="ButtonOK">OK</BUTTON><BR>
<BUTTON STYLE="WIDTH:100" ID="ButtonCancel">Cancel</BUTTON>
</TD>
</TR>
<TR WIDTH=100% HEIGHT=75>
<TD ALIGN=CENTER VALIGN=BOTTOM>
TODO: Place controls here.
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

Binary file not shown.

View File

@@ -0,0 +1,256 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "About CAlfrescoApp"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
ICON 128,IDC_STATIC,11,17,20,20
LTEXT "CAlfrescoApp Version 1.0",IDC_STATIC,40,10,119,8,
SS_NOPREFIX
LTEXT "Copyright (C) 2005",IDC_STATIC,40,25,119,8
DEFPUSHBUTTON "OK",IDOK,178,7,50,16,WS_GROUP
END
IDD_CALFRESCOAPP_DIALOG DIALOGEX 0, 0, 469, 156
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE |
WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "Alfresco Check In/Out"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
PUSHBUTTON "OK",IDOK,209,130,50,13
LTEXT "Checked in 99 files",IDC_MSGTEXT,25,22,418,8
LISTBOX IDC_FILELIST,23,38,424,83,LBS_SORT |
LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
END
/////////////////////////////////////////////////////////////////////////////
//
// HTML
//
IDR_HTML_CALFRESCOAPP_DIALOG HTML "CAlfrescoApp.htm"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "Alfresco"
VALUE "FileDescription", "Alfresco Check In/Out"
VALUE "FileVersion", "1.0.0.1"
VALUE "InternalName", "CAlfrescoApp.exe"
VALUE "LegalCopyright", "(c) Alfresco. All rights reserved."
VALUE "OriginalFilename", "CAlfrescoApp.exe"
VALUE "ProductName", "Alfresco"
VALUE "ProductVersion", "1.0.0.1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_ABOUTBOX, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 228
TOPMARGIN, 7
BOTTOMMARGIN, 48
END
IDD_CALFRESCOAPP_DIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 462
TOPMARGIN, 7
BOTTOMMARGIN, 149
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_ABOUTBOX "&About CAlfrescoApp..."
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (U.K.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"#define _AFX_NO_SPLITTER_RESOURCES\r\n"
"#define _AFX_NO_OLE_RESOURCES\r\n"
"#define _AFX_NO_TRACKER_RESOURCES\r\n"
"#define _AFX_NO_PROPERTY_RESOURCES\r\n"
"\r\n"
"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
"LANGUAGE 9, 1\r\n"
"#pragma code_page(1252)\r\n"
"#include ""res\\CAlfrescoApp.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
"#include ""afxres.rc"" // Standard components\r\n"
"#endif\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "alfresco.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_FILESTATUS DIALOGEX 0, 0, 448, 332
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "Alfresco File Status"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,391,311,50,14
CONTROL "",IDC_FILELIST,"SysListView32",LVS_REPORT |
LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,434,299
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_FILESTATUS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 441
TOPMARGIN, 7
BOTTOMMARGIN, 325
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.K.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#define _AFX_NO_SPLITTER_RESOURCES
#define _AFX_NO_OLE_RESOURCES
#define _AFX_NO_TRACKER_RESOURCES
#define _AFX_NO_PROPERTY_RESOURCES
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE 9, 1
#pragma code_page(1252)
#include "res\CAlfrescoApp.rc2" // non-Microsoft Visual C++ edited resources
#include "afxres.rc" // Standard components
#endif
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CAlfrescoApp", "CAlfrescoApp.vcproj", "{055DCC85-2D1A-4594-B2BE-ED292D2BF26D}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{055DCC85-2D1A-4594-B2BE-ED292D2BF26D}.Debug.ActiveCfg = Debug|Win32
{055DCC85-2D1A-4594-B2BE-ED292D2BF26D}.Debug.Build.0 = Debug|Win32
{055DCC85-2D1A-4594-B2BE-ED292D2BF26D}.Release.ActiveCfg = Release|Win32
{055DCC85-2D1A-4594-B2BE-ED292D2BF26D}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

Binary file not shown.

View File

@@ -0,0 +1,294 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="CAlfrescoApp"
ProjectGUID="{055DCC85-2D1A-4594-B2BE-ED292D2BF26D}"
RootNamespace="CAlfrescoApp"
Keyword="MFCProj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
UseOfMFC="2"
CharacterSet="1">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=".\includes"
PreprocessorDefinitions="UNICODE"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
TreatWChar_tAsBuiltInType="TRUE"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="mpr.lib shell32.lib"
OutputFile="$(OutDir)/Alfresco.exe"
LinkIncremental="2"
GenerateDebugInformation="TRUE"
SubSystem="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="FALSE"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"
AdditionalIncludeDirectories="$(IntDir)"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
UseOfMFC="2"
CharacterSet="1">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=".\includes"
PreprocessorDefinitions="UNICODE"
MinimalRebuild="FALSE"
RuntimeLibrary="2"
TreatWChar_tAsBuiltInType="TRUE"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="mpr.lib shell32.lib"
OutputFile="$(OutDir)/Alfresco.exe"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="FALSE"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"
AdditionalIncludeDirectories="$(IntDir)"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\CAlfrescoApp.cpp">
</File>
<File
RelativePath=".\CAlfrescoAppDlg.cpp">
</File>
<File
RelativePath=".\FileStatusDialog.cpp">
</File>
<File
RelativePath=".\stdafx.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
<Filter
Name="util"
Filter="">
<File
RelativePath=".\source\util\ByteArray.cpp">
</File>
<File
RelativePath=".\source\util\DataBuffer.cpp">
</File>
<File
RelativePath=".\source\util\DataPacker.cpp">
</File>
<File
RelativePath=".\source\util\Exception.cpp">
</File>
<File
RelativePath=".\source\util\FileName.cpp">
</File>
<File
RelativePath=".\source\util\Integer.cpp">
</File>
<File
RelativePath=".\source\util\Long.cpp">
</File>
<File
RelativePath=".\source\util\String.cpp">
</File>
<File
RelativePath=".\source\util\System.cpp">
</File>
</Filter>
<Filter
Name="alfresco"
Filter="">
<File
RelativePath=".\source\alfresco\Alfresco.cpp">
</File>
</Filter>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\CAlfrescoApp.h">
</File>
<File
RelativePath=".\CAlfrescoAppDlg.h">
</File>
<File
RelativePath=".\FileStatusDialog.h">
</File>
<File
RelativePath=".\Resource.h">
</File>
<File
RelativePath=".\stdafx.h">
</File>
<Filter
Name="util"
Filter="">
<File
RelativePath=".\includes\util\ByteArray.h">
</File>
<File
RelativePath=".\includes\util\DataBuffer.h">
</File>
<File
RelativePath=".\includes\util\DataPacker.h">
</File>
<File
RelativePath=".\includes\util\Exception.h">
</File>
<File
RelativePath=".\includes\util\FileName.h">
</File>
<File
RelativePath=".\includes\util\Integer.h">
</File>
<File
RelativePath=".\includes\util\JavaTypes.h">
</File>
<File
RelativePath=".\includes\util\Long.h">
</File>
<File
RelativePath=".\includes\util\String.h">
</File>
<File
RelativePath=".\includes\util\System.h">
</File>
<File
RelativePath=".\includes\util\Types.h">
</File>
</Filter>
<Filter
Name="alfresco"
Filter="">
<File
RelativePath=".\includes\alfresco\Alfresco.hpp">
</File>
</Filter>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
<File
RelativePath=".\alfresco.ico">
</File>
<File
RelativePath=".\res\CAlfrescoApp.ico">
</File>
<File
RelativePath=".\CAlfrescoApp.rc">
</File>
<File
RelativePath=".\res\CAlfrescoApp.rc2">
</File>
</Filter>
<File
RelativePath=".\CAlfrescoApp.htm"
DeploymentContent="TRUE">
</File>
<File
RelativePath=".\res\CAlfrescoApp.manifest">
</File>
<File
RelativePath=".\ReadMe.txt">
</File>
</Files>
<Globals>
<Global
Name="RESOURCE_FILE"
Value="CAlfrescoApp.rc"/>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,164 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "stdafx.h"
#include "CAlfrescoApp.h"
#include "CAlfrescoAppDlg.h"
#include ".\calfrescoappdlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
CCAlfrescoAppDlg::CCAlfrescoAppDlg(CWnd* pParent /*=NULL*/)
: CDialog( CCAlfrescoAppDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
}
void CCAlfrescoAppDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CCAlfrescoAppDlg, CDialog)
ON_WM_SYSCOMMAND()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// CCAlfrescoAppDlg message handlers
BOOL CCAlfrescoAppDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
void CCAlfrescoAppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CCAlfrescoAppDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CCAlfrescoAppDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#pragma once
// CCAlfrescoAppDlg dialog
class CCAlfrescoAppDlg : public CDialog
{
// Construction
public:
CCAlfrescoAppDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
enum { IDD = IDD_CALFRESCOAPP_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
};

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "stdafx.h"
#include "CAlfrescoApp.h"
#include "FileStatusDialog.h"
#include "util\Long.h"
// CFileStatusDialog dialog
IMPLEMENT_DYNAMIC(CFileStatusDialog, CDialog)
CFileStatusDialog::CFileStatusDialog(AlfrescoFileInfoList& fileList, CWnd* pParent /*=NULL*/)
: CDialog(CFileStatusDialog::IDD, pParent),
m_fileList( fileList)
{
}
CFileStatusDialog::~CFileStatusDialog()
{
}
void CFileStatusDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_FILELIST, m_listCtrl);
}
BEGIN_MESSAGE_MAP(CFileStatusDialog, CDialog)
END_MESSAGE_MAP()
/**
* Initialize the dialog
*/
BOOL CFileStatusDialog::OnInitDialog() {
// Call the base class
CDialog::OnInitDialog();
// Add headers to the list control
m_listCtrl.InsertColumn( 0, L"Name", LVCFMT_LEFT, 200);
m_listCtrl.InsertColumn( 1, L"Mime-type", LVCFMT_LEFT, 140);
m_listCtrl.InsertColumn( 2, L"Size", LVCFMT_RIGHT, 80);
m_listCtrl.InsertColumn( 3, L"Status", LVCFMT_LEFT, 100);
m_listCtrl.InsertColumn( 4, L"Owner", LVCFMT_LEFT, 100);
// Add the list view data
for ( unsigned int i = 0; i < m_fileList.size(); i++) {
// Get the current file information
const AlfrescoFileInfo* pInfo = m_fileList.getInfoAt( i);
// Add the item to the list view
if ( pInfo != NULL) {
// Insert a new item in the view
int nIndex = m_listCtrl.InsertItem( 0, pInfo->getName());
if ( pInfo->isType() == TypeFile) {
// Display the mime-type and content length
m_listCtrl.SetItemText( nIndex, 1, pInfo->getContentType());
m_listCtrl.SetItemText( nIndex, 2, Long::toString( pInfo->getContentLength()));
String status;
String owner;
if ( pInfo->isWorkingCopy()) {
status = L"Work";
}
else if ( pInfo->getLockType() != LockNone) {
status = L"Locked";
owner = pInfo->getLockOwner();
}
m_listCtrl.SetItemText( nIndex, 3, status);
m_listCtrl.SetItemText( nIndex, 4, owner);
}
}
}
// Clear the file info list
m_fileList.clear();
return FALSE;
}
// CFileStatusDialog message handlers

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#pragma once
#include "afxcmn.h"
#include "alfresco\Alfresco.hpp"
// CFileStatusDialog dialog
class CFileStatusDialog : public CDialog
{
DECLARE_DYNAMIC(CFileStatusDialog)
public:
CFileStatusDialog( AlfrescoFileInfoList& fileList, CWnd* pParent = NULL); // standard constructor
virtual ~CFileStatusDialog();
// Dialog Data
enum { IDD = IDD_FILESTATUS };
// Initialize the dialog
BOOL OnInitDialog();
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
CListCtrl m_listCtrl;
protected:
// File information list
AlfrescoFileInfoList& m_fileList;
};

View File

@@ -0,0 +1,40 @@
// FileStatusView.cpp : implementation file
//
#include "stdafx.h"
#include "CAlfrescoApp.h"
#include "FileStatusView.h"
// CFileStatusView
IMPLEMENT_DYNCREATE(CFileStatusView, CListView)
CFileStatusView::CFileStatusView()
{
}
CFileStatusView::~CFileStatusView()
{
}
BEGIN_MESSAGE_MAP(CFileStatusView, CListView)
END_MESSAGE_MAP()
// CFileStatusView diagnostics
#ifdef _DEBUG
void CFileStatusView::AssertValid() const
{
CListView::AssertValid();
}
void CFileStatusView::Dump(CDumpContext& dc) const
{
CListView::Dump(dc);
}
#endif //_DEBUG
// CFileStatusView message handlers

View File

@@ -0,0 +1,24 @@
#pragma once
// CFileStatusView view
class CFileStatusView : public CListView
{
DECLARE_DYNCREATE(CFileStatusView)
protected:
CFileStatusView(); // protected constructor used by dynamic creation
virtual ~CFileStatusView();
public:
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
DECLARE_MESSAGE_MAP()
};

View File

@@ -0,0 +1,90 @@
================================================================================
MICROSOFT FOUNDATION CLASS LIBRARY : CAlfrescoApp Project Overview
===============================================================================
The application wizard has created this CAlfrescoApp application for
you. This application not only demonstrates the basics of using the Microsoft
Foundation Classes but is also a starting point for writing your application.
This file contains a summary of what you will find in each of the files that
make up your CAlfrescoApp application.
CAlfrescoApp.vcproj
This is the main project file for VC++ projects generated using an application wizard.
It contains information about the version of Visual C++ that generated the file, and
information about the platforms, configurations, and project features selected with the
application wizard.
CAlfrescoApp.h
This is the main header file for the application. It includes other
project specific headers (including Resource.h) and declares the
CCAlfrescoAppApp application class.
CAlfrescoApp.cpp
This is the main application source file that contains the application
class CCAlfrescoAppApp.
CAlfrescoApp.rc
This is a listing of all of the Microsoft Windows resources that the
program uses. It includes the icons, bitmaps, and cursors that are stored
in the RES subdirectory. This file can be directly edited in Microsoft
Visual C++. Your project resources are in 1033.
res\CAlfrescoApp.ico
This is an icon file, which is used as the application's icon. This
icon is included by the main resource file CAlfrescoApp.rc.
res\CAlfrescoApp.rc2
This file contains resources that are not edited by Microsoft
Visual C++. You should place all resources not editable by
the resource editor in this file.
/////////////////////////////////////////////////////////////////////////////
The application wizard creates one dialog class:
CAlfrescoAppDlg.h, CAlfrescoAppDlg.cpp - the dialog
These files contain your CCAlfrescoAppDlg class. This class defines
the behavior of your application's main dialog. The dialog's template is
in CAlfrescoApp.rc, which can be edited in Microsoft Visual C++.
/////////////////////////////////////////////////////////////////////////////
Other Features:
ActiveX Controls
The application includes support to use ActiveX controls.
/////////////////////////////////////////////////////////////////////////////
Other standard files:
StdAfx.h, StdAfx.cpp
These files are used to build a precompiled header (PCH) file
named CAlfrescoApp.pch and a precompiled types file named StdAfx.obj.
Resource.h
This is the standard header file, which defines new resource IDs.
Microsoft Visual C++ reads and updates this file.
CAlfrescoApp.manifest
Application manifest files are used by Windows XP to describe an applications
dependency on specific versions of Side-by-Side assemblies. The loader uses this
information to load the appropriate assembly from the assembly cache or private
from the application. The Application manifest maybe included for redistribution
as an external .manifest file that is installed in the same folder as the application
executable or it may be included in the executable in the form of a resource.
/////////////////////////////////////////////////////////////////////////////
Other notes:
The application wizard uses "TODO:" to indicate parts of the source code you
should add to or customize.
If your application uses MFC in a shared DLL, and your application is in a
language other than the operating system's current language, you will need
to copy the corresponding localized resources MFC70XXX.DLL from the Microsoft
Visual C++ CD-ROM under the Win\System directory to your computer's system or
system32 directory, and rename it to be MFCLOC.DLL. ("XXX" stands for the
language abbreviation. For example, MFC70DEU.DLL contains resources
translated to German.) If you don't do this, some of the UI elements of
your application will remain in the language of the operating system.
/////////////////////////////////////////////////////////////////////////////

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

View File

@@ -0,0 +1,302 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _Alfresco_H
#define _Alfresco_H
// Includes
#include <windows.h>
#include <WinIOCtl.h>
#include <vector>
#include <algorithm>
#include "util\Exception.h"
#include "util\String.h"
#include "util\DataBuffer.h"
// Classes defined in this header file
namespace Alfresco {
class AlfrescoInterface;
class AlfrescoFileInfo;
class AlfrescoFileInfoList;
typedef std::auto_ptr<AlfrescoFileInfo> PTR_AlfrescoFileInfo;
}
// Constants
namespace Alfresco {
// Alfresco I/O control codes
#define FSCTL_ALFRESCO_PROBE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_ALFRESCO_FILESTS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_ALFRESCO_CHECKOUT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x802, METHOD_BUFFERED, FILE_WRITE_DATA)
#define FSCTL_ALFRESCO_CHECKIN CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x803, METHOD_BUFFERED, FILE_WRITE_DATA)
// Request signature bytes
#define IOSignature "ALFRESCO"
#define IOSignatureLen 8
// Path prefixes/components
#define UNCPathPrefix L"\\\\"
#define PathSeperator L"\\"
// I/O control status codes
#define StsSuccess 0
#define StsError 1
#define StsFileNotFound 2
#define StsAccessDenied 3
#define StsBadParameter 4
#define StsNotWorkingCopy 5
// Boolean field values
#define True 1
#define False 0
// File status field values
//
// Node type
#define TypeFile 0
#define TypeFolder 1
// Lock status
#define LockNone 0
#define LockRead 1
#define LockWrite 2
}
// Define Alfresco interface exceptions
DEFINE_EXCEPTION(Alfresco, BadInterfaceException);
/**
* Alfresco API Class
*
* Provides the interface to an Alfresco CIFS server to perform Alfresco specific functions
* not available via the normal file I/O functions.
*/
class Alfresco::AlfrescoInterface {
public:
// Class constructors
AlfrescoInterface(String& path);
// Class destructor
~AlfrescoInterface();
// Return the UNC path and root path
inline const String& getUNCPath( void) const { return m_uncPath; }
inline const String& getRootPath( void) const { return m_rootPath; }
// Check if the application is running from a mapped drive, return the drive path
inline bool isMappedDrive( void) const { return m_mappedDrive.length() > 0 ? true : false; }
inline const String& getDrivePath( void) const { return m_mappedDrive; }
// Check if the path is on an Alfresco CIFS server
bool isAlfrescoFolder( void);
// Return the Alfresco file information for a file/folder within the current folder
PTR_AlfrescoFileInfo getFileInformation(const wchar_t* fileName);
// Check in a working copy file
void checkIn( const wchar_t* fileName, bool keepCheckedOut = false);
// Check out a file
void checkOut( const wchar_t* fileName, String& workingCopy);
private:
// Send an I/O control request, receive and validate the response
void sendIOControl( const unsigned int ctlCode, DataBuffer& reqbuf, DataBuffer& respbuf);
private:
// Hide the copy constructor
AlfrescoInterface(const AlfrescoInterface& alfresco) {};
private:
// Instance variables
//
// UNC path and root path
String m_uncPath;
String m_rootPath;
// Local path letter if running from a mapped drive
String m_mappedDrive;
// Handle to folder
HANDLE m_handle;
};
/**
* Alfresco File Information Class
*
* Contains Alfresco specific file information for a file/folder on an Alfresco CIFS server.
*/
class Alfresco::AlfrescoFileInfo {
public:
// Class constructor
AlfrescoFileInfo( const wchar_t* fName);
// Return the file/folder name
inline const String& getName( void) const { return m_name; }
// Determine if the file is a file or folder
inline unsigned int isType( void) const { return m_type; }
// Return the working copy status, owner, copied from
inline bool isWorkingCopy( void) const { return m_workingCopy; }
inline const String& getCopyOwner( void) const { return m_workOwner; }
inline const String& getCopiedFrom( void) const { return m_copiedFrom; }
// Return the lock status
inline unsigned int getLockType( void) const { return m_lockType; }
inline const String& getLockOwner( void) const { return m_lockOwner; }
// Return the content details
inline bool hasContent( void) const { return m_hasContent; }
inline LONG64 getContentLength( void) const { return m_contentLen; }
inline const String& getContentType( void) const { return m_contentMimeType; }
// Set the file/folder type
inline void setType( unsigned int typ) { m_type = typ; }
// Set the working copy owner and copied from
void setWorkingCopy( const wchar_t* owner, const wchar_t* copiedFrom);
// Set the lock type and owner
void setLockType( unsigned int typ, const wchar_t* owner = L"");
// Set the content length and type
void setContent( LONG64 siz, const wchar_t* mimeType);
// Operators
bool operator==( const AlfrescoFileInfo& finfo);
bool operator<( const AlfrescoFileInfo& finfo);
private:
// Hide the copy constructor
AlfrescoFileInfo(const AlfrescoFileInfo& aInfo) {};
private:
// Instance variables
//
// File/folder name
String m_name;
unsigned int m_type;
// Working copy flag, owner and copied from
bool m_workingCopy;
String m_workOwner;
String m_copiedFrom;
// Lock type and owner
unsigned int m_lockType;
String m_lockOwner;
// Content mime-type and length
bool m_hasContent;
LONG64 m_contentLen;
String m_contentMimeType;
};
/**
* Alfresco File Info List Class
*/
class Alfresco::AlfrescoFileInfoList {
public:
// Class constructor
AlfrescoFileInfoList( void) {};
// Add a file information object to the list
inline void addInfo( AlfrescoFileInfo* pInfo) { m_list.push_back( pInfo); }
inline void addInfo( PTR_AlfrescoFileInfo pInfo) { if ( pInfo.get() != NULL) m_list.push_back( pInfo.release()); }
// Return the number of objects in the list
inline size_t size( void) const { return m_list.size(); }
// Return the specified file information
inline const AlfrescoFileInfo* getInfoAt( unsigned int idx) const { return m_list[idx]; }
// Assignment operator
inline AlfrescoFileInfo*& operator[] ( const unsigned int idx) { return m_list[idx]; }
// Remove all objects from the list
inline void clear( void) { for ( unsigned int i = 0; i < m_list.size(); delete m_list[i++]); m_list.clear(); }
// Return the vector
std::vector<AlfrescoFileInfo*> getList( void) { return m_list; }
private:
// Instance variables
//
// List of file information objects
std::vector<AlfrescoFileInfo*> m_list;
};
#endif

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _ByteArray_H
#define _ByteArray_H
// Includes
#include <memory>
#include <string>
#include "util\Types.h"
// Classes defined in this header file
namespace Alfresco {
class ByteArray;
typedef std::auto_ptr<ByteArray> PTR_ByteArray;
}
/**
* Byte Array Class
*
* Provides a byte array object similar to Javas byte[].
*/
class Alfresco::ByteArray {
public:
// Constructors
ByteArray( BUFLEN len = 0, bool clearMem = false);
ByteArray( CBUFPTR data, BUFLEN len);
ByteArray( const char* data, BUFLEN len);
// Copy constructor
ByteArray( const ByteArray& byts);
// Class destructor
~ByteArray();
// Return the data/length
inline CBUFPTR getData( void) const { return m_data; }
inline BUFPTR getData( void) { return m_data; }
inline BUFLEN getLength( void) const { return m_length; }
// Set the array length
void setLength( BUFLEN len, bool clearMem = false);
// Set a byte
void setByte( unsigned int idx, unsigned char val);
// Subscript operator
unsigned char& operator[](const unsigned int idx);
// Assignment operator
ByteArray& operator=( const ByteArray& byts);
ByteArray& operator=( std::string& byts);
// Equality operator
bool operator== ( const ByteArray& byts);
// Return the start address of the byte array
operator const unsigned char* ( void) { return m_data; }
protected:
// Set the byte array and length
void setData( CBUFPTR data, BUFLEN len);
private:
// Instance variables
//
// Byte data and length
BUFPTR m_data;
BUFLEN m_length;
};
#endif

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _DataBuffer_H
#define _DataBuffer_H
// Includes
#include "util\DataPacker.h"
// Classes defined in this header file
namespace Alfresco {
class DataBuffer;
typedef std::auto_ptr<DataBuffer> PTR_DataBuffer;
}
// Constants
namespace Alfresco {
// Default data buffer size
#define DataBufferDefaultSize 256
}
/**
* Data Buffer Class
*
* Dynamic buffer for getting/setting data blocks.
*/
class Alfresco::DataBuffer {
public:
// Class constructors
DataBuffer( unsigned int siz = DataBufferDefaultSize);
DataBuffer( BUFPTR buf, BUFPOS off, BUFLEN len);
// Class destructor
~DataBuffer();
// Getter methods
inline BUFPTR getBuffer( void) { return m_buf; }
BUFLEN getLength( void) const;
unsigned int getLengthInWords( void) const;
BUFLEN getAvailableLength( void) const;
inline BUFLEN getBufferLength(void) const { return m_buflen; }
inline unsigned int getDisplacement( void) const { return m_pos - m_offset; }
inline BUFPOS getOffset( void) { return m_offset; }
inline BUFPOS getPosition( void) { return m_pos; }
// Get data items from the buffer
unsigned char getByte( void);
unsigned int getShort( void);
unsigned int getInt( void);
LONG64 getLong( void);
String getString( bool uni = true);
String getString( unsigned int maxLen, bool uni = true);
unsigned int getShortAt( unsigned int idx);
unsigned int getIntAt( unsigned int idx);
LONG64 getLongAt( unsigned int idx);
// Put data items into the buffer
void putByte( unsigned char byt);
void putShort( unsigned int sval);
void putInt( unsigned int ival);
void putLong( LONG64 lval);
void putShortAt( unsigned int idx, unsigned int sval);
void putIntAt( unsigned int idx, unsigned int ival);
void putLongAt( unsigned int idx, LONG64 lval);
void putString( const String& str, bool uni = true, bool nulTerm = true);
void putFixedString( const String& str, unsigned int len);
BUFPOS putStringAt( const String& str, BUFPOS pos, bool uni = true, bool nulTerm = true);
BUFPOS putFixedStringAt( const String& str, unsigned int len, BUFPOS pos);
void putStringPointer( unsigned int off);
void putZeros( unsigned int cnt);
// Align the buffer position
void wordAlign( void);
void longwordAlign( void);
// Append a raw data block to the buffer
void appendData( BUFPTR buf, BUFPOS off, BUFLEN len);
// Copy the data to the user buffer and update the read position
unsigned int copyData( BUFPTR buf, BUFPOS pos, unsigned int cnt);
// Skip data items in the buffer
void skipBytes( unsigned int len);
// Setter methods
inline void setPosition( BUFPOS pos) { m_pos = pos; }
void setEndOfBuffer( void);
void setLength( BUFLEN len);
private:
// Extend the buffer
void extendBuffer( BUFLEN ext);
void extendBuffer( void);
protected:
// Instance variables
//
// Data buffer
BUFPTR m_buf;
unsigned int m_buflen;
// Flag to indicate if the buffer is owned by this object
bool m_owner;
// Buffer positions/offsets
BUFPOS m_pos;
BUFPOS m_endpos;
BUFPOS m_offset;
};
#endif

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _DataPacker_H
#define _DataPacker_H
// Includes
#include "util\String.h"
#include "util\Types.h"
#include "util\JavaTypes.h"
// Classes defined in this header file
namespace Alfresco {
class DataPacker;
}
/**
* DataPacker Class
*
* The DataPacker class provides methods for packing and unpacking of various data types from a buffer.
*/
class Alfresco::DataPacker {
private:
// Hide constructors
DataPacker( void) {};
DataPacker(const DataPacker& dp) {};
public:
// Unpack data types from a buffer
static int getShort(CBUFPTR buf, BUFPOS pos);
static int getInt(CBUFPTR buf, BUFPOS pos);
static LONG64 getLong(CBUFPTR buf, BUFPOS pos);
static int getIntelShort(CBUFPTR buf, BUFPOS pos);
static int getIntelInt(CBUFPTR buf, BUFPOS pos);
static LONG64 getIntelLong(CBUFPTR buf, BUFPOS pos);
static String getString(CBUFPTR buf, BUFPOS pos, const unsigned int maxLen, const bool isUni = false);
static String getUnicodeString(CBUFPTR buf, BUFPOS pos, const unsigned int maxLen);
// Pack data types into a buffer
static void putShort(const int val, BUFPTR buf, BUFPOS pos);
static void putInt(const int val, BUFPTR buf, BUFPOS pos);
static void putLong(const LONG64 val, BUFPTR buf, BUFPOS pos);
static void putIntelShort(const int val, BUFPTR buf, BUFPOS pos);
static void putIntelInt(const int val, BUFPTR buf, BUFPOS pos);
static void putIntelLong(const LONG64 val, BUFPTR buf, BUFPOS pos);
static unsigned int putString(const String& str, BUFPTR buf, BUFPOS pos, bool nullTerm = true, bool isUni = false);
static unsigned int putString(const char* str, BUFLEN len, BUFPTR buf, BUFPOS pos, bool nullTerm = true);
static unsigned int putString(const wchar_t* str, BUFLEN len, BUFPTR buf, BUFPOS pos, bool nullTerm = true);
static void putZeros(BUFPTR buf, BUFPOS pos, const unsigned int count);
// Calculate buffer positions
static unsigned int getStringLength(const String& str, const bool isUni = false, const bool nulTerm = false);
static unsigned int getBufferPosition(BUFPOS pos, const String& str, const bool isUni = false, const bool nulTerm = false);
// Align a buffer offset
static inline BUFPOS longwordAlign( BUFPOS pos) { return ( pos + 3) & 0xFFFFFFFC; }
static inline BUFPOS wordAlign( BUFPOS pos) { return ( pos + 1) & 0xFFFFFFFE; }
};
#endif

View File

@@ -0,0 +1,130 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _JavaException_H
#define _JavaException_H
// Includes
#include "util\String.h"
// Classes defined in this header file
namespace Alfresco {
class Exception;
class IOException;
}
// Macro to check for null and throw a null pointer exception
#define NULL_POINTER_CHECK(p,m) if(p==NULL) throw NullPointerException(m)
/**
* Java-like Exception Class
*
* Used as a base class for all Java-like exception classes.
*/
class Alfresco::Exception {
public:
// Constructors
Exception( const wchar_t* msg = NULL, const wchar_t* msg2 = NULL, const wchar_t* msg3 = NULL, const wchar_t* msg4 = NULL, const wchar_t* msg5 = NULL);
Exception( const char* moduleName, unsigned int lineNum, const wchar_t* msg = NULL, const wchar_t* msg2 = NULL, const wchar_t* msg3 = NULL, const wchar_t* msg4 = NULL, const wchar_t* msg5 = NULL);
// Copy constructor
Exception( const Exception& ex);
// Class destructor
~Exception();
// Return the exception message
inline const String& getMessage( void) const { return m_msg; }
// Return the exception as a string
inline const String& toString( void) const { return m_msg; }
private:
// Instance variables
//
// Exception message
String m_msg;
};
// Macros to declare an exception class
#define DEFINE_EXCEPTION(ns,ex) namespace ns { class ex : public Exception { \
public: \
ex( const char* modName, unsigned int lineNum, const wchar_t* msg = NULL, const wchar_t* msg2 = NULL, const wchar_t* msg3 = NULL, const wchar_t* msg4 = NULL, const wchar_t* msg5 = NULL); \
ex( const wchar_t* msg = NULL, const wchar_t* msg2 = NULL, const wchar_t* msg3 = NULL, const wchar_t* msg4 = NULL, const wchar_t* msg5 = NULL); }; }
#define DEFINE_IOEXCEPTION(ns,ex) namespace ns { class ex : public IOException { \
public: \
ex( const char* modName, unsigned int lineNum, const wchar_t* msg = NULL, const wchar_t* msg2 = NULL, const wchar_t* msg3 = NULL, const wchar_t* msg4 = NULL, const wchar_t* msg5 = NULL); \
ex( const wchar_t* msg = NULL, const wchar_t* msg2 = NULL, const wchar_t* msg3 = NULL, const wchar_t* msg4 = NULL, const wchar_t* msg5 = NULL); }; }
// Macros to define new exception class code, should be used in a module not a header
#define EXCEPTION_CLASS(ns,ex) \
ex :: ex( const char* modName, unsigned int lineNum, const wchar_t* msg, const wchar_t* msg2, const wchar_t* msg3, const wchar_t* msg4, const wchar_t* msg5) : \
Exception(modName,lineNum,msg,msg2,msg3,msg4,msg5) {} \
ex :: ex( const wchar_t* msg, const wchar_t* msg2, const wchar_t* msg3, const wchar_t* msg4, const wchar_t* msg5) : \
Exception(msg,msg2,msg3,msg4,msg5) {}
// Define the IOException class
DEFINE_EXCEPTION(Alfresco,IOException);
// Define the macro create new IOException based exceptions
#define IOEXCEPTION_CLASS(ns,ex) \
ex :: ex( const char* modName, unsigned int lineNum, const wchar_t* msg, const wchar_t* msg2, const wchar_t* msg3, const wchar_t* msg4, const wchar_t* msg5) : \
IOException(modName,lineNum,msg,msg2,msg3,msg4,msg5) {} \
ex :: ex( const wchar_t* msg, const wchar_t* msg2, const wchar_t* msg3, const wchar_t* msg4, const wchar_t* msg5) : \
IOException(msg,msg2,msg3,msg4,msg5) {}
// Define standard exceptions
DEFINE_EXCEPTION(Alfresco,NullPointerException);
DEFINE_EXCEPTION(Alfresco,ArrayIndexOutOfBoundsException);
DEFINE_EXCEPTION(Alfresco,NumberFormatException);
DEFINE_IOEXCEPTION(Alfresco, AccessDeniedException);
DEFINE_IOEXCEPTION(Alfresco, DirectoryNotEmptyException);
DEFINE_IOEXCEPTION(Alfresco, DiskFullException);
DEFINE_IOEXCEPTION(Alfresco, FileExistsException);
DEFINE_IOEXCEPTION(Alfresco, FileOfflineException);
DEFINE_IOEXCEPTION(Alfresco, FileSharingException);
DEFINE_IOEXCEPTION(Alfresco, FileNotFoundException);
DEFINE_IOEXCEPTION(Alfresco, PathNotFoundException);
DEFINE_IOEXCEPTION(Alfresco, FileLockException);
DEFINE_IOEXCEPTION(Alfresco, FileUnlockException);
DEFINE_IOEXCEPTION(Alfresco, LockConflictException);
DEFINE_IOEXCEPTION(Alfresco, NotLockedException);
#endif

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _FileName_H
#define _FileName_H
// Includes
#include "util\String.h"
// Classes defined in this header file
namespace Alfresco {
class FileName;
}
/**
* File Naming Utility Class
*
* Contains various utility methods for building and splitting file paths.
*/
class Alfresco::FileName {
public:
// Build a path using the specified components
static const String buildPath( const String& dev, const String& path, const String& fileName, wchar_t sep = L'\\');
// Check if a file name contains a stream name
static bool containsStreamName( const String& fileName);
// Convert path separator characters
static const String convertSeperators( const String& path, wchar_t sep);
// Make a relative path
static const String makeRelativePath( const String& basePath, const String& fullPath);
// Map an input path to a real path
static const String mapPath(const String& base, const String& path);
// Normalize a path converting all directories to uppercase and keeping the file name as is
static const String normalizePath(const String& path);
// Remove the file name from the path
static const String removeFileName(const String& path);
// Split the path into all the component directories and filename
static StringList splitAllPaths(const String& path);
// Split the path into separate directory path and file name strings
static StringList splitPath( const String& path, wchar_t sep = L'\\');
// Split a path string into directory path, file name and stream name components
static StringList splitPathStream( const String& path);
public:
// Constant values
static String& DosSeperator;
static String& NTFSStreamSeperator;
static wchar_t DOS_SEPERATOR;
private:
// Hide constructors, static only class
FileName( void) {};
FileName( const FileName& fname) {};
};
#endif

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _JavaInteger_H
#define _JavaInteger_H
// Includes
#include "util\String.h"
#include "util\Exception.h"
#include "util\Types.h"
// Classes defined in this header file
namespace Alfresco {
class Integer;
}
/**
* Java-like Integer Class
*
* Provides static methods to convert integer values to strings.
*/
class Alfresco::Integer {
public:
// Convert an integer to a hexadecimal string
static String toHexString( const unsigned int ival);
static String toHexString( BUFPTR ptr);
// Convert an integer value to a string
static String toString( unsigned int ival, unsigned int radix = 10);
// Parse a string to generate an integer value
static unsigned int parseInt( const String& str, unsigned int radix = 10);
private:
// Hide constructors, static only class
Integer( void);
Integer(Integer& ival);
};
#endif

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _JavaTypes_H
#define _JavaTypes_H
// Typedefs for Java primitive types
typedef __int64 LONG64;
#endif

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _JavaLong_H
#define _JavaLong_H
// Includes
#include <windows.h>
#include "util\String.h"
#include "util\Exception.h"
#include "util\JavaTypes.h"
// Classes defined in this header file
namespace Alfresco {
class Long;
}
/**
* Java-like Long Class
*
* Provides static methods to convert long/64 bit values to strings.
*/
class Alfresco::Long {
public:
// Convert a long/64 bit integer to a hexadecimal string
static String toHexString( const LONG64 lval);
// Convert a long/64 bit integer to a decimal string
static String toString( const LONG64 lval);
// Make a long/64bit value from the low/high 32bit values
static LONG64 makeLong( unsigned int lowPart, unsigned int highPart);
static LONG64 makeLong( FILETIME fTime);
// Get the low/high 32bit values from a 64bit value
static bool hasHighPart( LONG64 lval) { return ( lval > 0xFFFFFFFF) ? true : false; }
static unsigned int getLowPart( LONG64 lval) { return (unsigned int) lval & 0xFFFFFFFF; }
static unsigned int getHighPart( LONG64 lval) { return (unsigned int) ((lval >> 32) & 0xFFFFFFFF); }
// Parse a string to generate a long/64 bit integer value
static LONG64 parseLong( const String& str, unsigned int radix = 10);
// Copy a long/64bit value to a FILETIME structure
static void copyTo( LONG64 lval, FILETIME& ftime);
private:
// Hide constructors, static only class
Long( void);
Long(Long& ival);
};
#endif

View File

@@ -0,0 +1,268 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _JavaString_H
#define _JavaString_H
// Includes
#include <string>
#include <vector>
#include <iostream>
#include "util\ByteArray.h"
#include "util\Types.h"
// Classes defined in this header file
namespace Alfresco {
class String;
class StringList;
}
/**
* Java-like String Class
*/
class Alfresco::String {
public:
// Constructors
String();
String(const unsigned int alloc);
String(const char* str);
String(const unsigned char* str);
String(const char* buf, const unsigned int offset, const unsigned int len);
String(const wchar_t* str);
String(const wchar_t* buf, const unsigned int offset, const unsigned int len);
String(const String& str);
String(const std::wstring& str);
String(ByteArray& byts);
// Return the string length
inline unsigned int length( void) const { return ( unsigned int) m_string.length(); }
// Check if a string is empty
inline bool isNull( void) const { return m_string.length() > 0 ? false : true; }
inline bool isNotEmpty( void) const { return m_string.length() > 0 ? true : false; }
// Compare strings for equality
bool equals(const wchar_t* str) const;
bool equals(const String& str) const;
bool equalsIgnoreCase(const wchar_t* str) const;
bool equalsIgnoreCase(const String& str) const;
// Compare strings
int compareTo( const String& str) const;
int compareTo( const wchar_t* pStr) const;
// Convert to lowercase/uppercase returning the new string
String toLowerCase() const;
String toUpperCase() const;
// Search for the occurrence of a character or string
int indexOf(const wchar_t ch, int startIndex = 0) const;
int indexOf(const wchar_t* str, int startIndex = 0) const;
int indexOf(const String& str, int startIndex = 0) const;
// Search for the occurrence of a character or string
int lastIndexOf(const wchar_t ch, int startIndex = -1) const;
int lastIndexOf(const wchar_t* str, int startIndex = -1) const;
int lastIndexOf(const String& str, int startIndex = -1) const;
// Check if the string starts with the specified string
bool startsWith(const wchar_t* str) const;
bool startsWith(const String& str) const;
bool startsWithIgnoreCase(const wchar_t* str) const;
bool startsWithIgnoreCase(const String& str) const;
// Check if the string ends with the specified string
bool endsWith(const wchar_t* str) const;
bool endsWith(const String& str) const;
// Replace all occurrences of the specified character in the string
void replace( wchar_t oldCh, wchar_t newCh);
// Append character, string, integer values to the string
void append( wchar_t ch);
void append( const char* str);
void append( const wchar_t* str);
void append( const String& str);
void append( const unsigned int ival);
void append( const unsigned long lval);
void append( const LONG64 l64val);
// Get the character at the specified position in the string
inline wchar_t charAt(const unsigned int idx) const { return m_string[idx]; }
// Set the string length
inline void setLength( unsigned int len) { m_string.resize( len, 0); }
// Trim leading and trailing whitespace from the string
String trim( void) const;
// Return the substring of this string
String substring( unsigned int beginIndex) const;
String substring( unsigned int beginIndex, unsigned int endIndex) const;
// Set the allocated capacity for the string by allocating or shrinking the current string buffer
inline void reserve( const unsigned int capacity = 0) { m_string.reserve( capacity); }
// Assignment operator
String& operator=(const wchar_t* str);
String& operator=(const String& str);
// Append operator
inline String& operator+=(wchar_t ch) { append( ch); return *this; }
inline String& operator+=(const char* str) { append( str); return *this; }
inline String& operator+=(const wchar_t* str) { append( str); return *this; }
inline String& operator+=(const String& str) { append( str); return *this; }
inline String& operator+=(const unsigned int ival) { append( ival); return *this; }
inline String& operator+=(const unsigned long lval) { append( lval); return *this; }
inline String& operator+=(const LONG64 l64val) { append( l64val); return *this; }
// Equality operator
bool operator== ( const String& str) const;
bool operator== ( const wchar_t* str) const;
bool operator== ( const char* str) const;
// Less than operator
bool operator< ( const String& str) const;
// Return the string data
inline const wchar_t* data() const { return m_string.data(); }
// Conversion operator
inline operator const wchar_t* ( void) const { return m_string.data(); }
// Return the string as an array of bytes
ByteArray getBytes( ByteArray& byts) const;
ByteArray getBytes( void) const;
// Split the string into tokens using the specified delimiters
StringList tokenize( const String& delims) const;
// Streaming operators
friend std::wostream& operator<<(std::wostream& out, const String& str);
friend std::ostream& operator<<(std::ostream& out, const String& str);
// Access the internal string object
inline std::wstring getString( void) { return m_string; }
inline const std::wstring getString( void) const { return m_string; }
private:
// String data
std::wstring m_string;
};
/**
* String List Class
*/
class Alfresco::StringList {
public:
// Class constructor
StringList( void);
StringList( unsigned int reserve);
StringList( const StringList& strList);
// Add a string to the list
inline void addString( const String& str) { m_list.push_back( str); }
// Check if the list contains the specified string
bool containsString( const String& str);
bool containsStringCaseless ( const String& str);
// Return the index of the specified string, or -1 if not found
int indexOf( const String& str) const;
// Remove a string from the list
void removeString( const String& str);
void removeStringCaseless( const String& str);
// Return the number of strings in the list
inline size_t numberOfStrings( void) const { return m_list.size(); }
// Return the specified string
inline const String& getStringAt( unsigned int idx) const { return m_list[idx]; }
// Assignment operator
inline String& operator[] ( const unsigned int idx) { return m_list[idx]; }
// Remove all strings from the list
inline void removeAllStrings( void) { m_list.clear(); }
// Copy the string list
void copyFrom( const StringList& strList);
// Return the string list as a comma separated list
String toString( void) const;
private:
// Instance variables
//
// List of strings
std::vector<String> m_list;
};
#endif

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _JavaSystem_H
#define _JavaSystem_H
// Includes
#include "util\Types.h"
// Classes defined in this header file
namespace Alfresco {
class System;
}
/**
* Java-like System Class
*/
class Alfresco::System {
public:
// Get the current system time in milliseconds
static DATETIME currentTimeMillis( void);
private:
// Hide constructors, static only class
System( void) {};
System ( const System& sys) {};
};
#endif

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#ifndef _AlfrescoTypes_H
#define _AlfrescoTypes_H
// Includes
#include "util\JavaTypes.h"
namespace Alfresco {
// Type definitions
//
// Data buffer pointer, position and length
typedef unsigned char* BUFPTR;
typedef unsigned int BUFPOS;
typedef unsigned int BUFLEN;
typedef const unsigned char* CBUFPTR;
typedef const unsigned int CBUFPOS;
typedef const unsigned int CBUFLEN;
// File position and length
typedef LONG64 FILEPOS;
typedef LONG64 FILELEN;
// Date/time
typedef LONG64 DATETIME;
#define NULL_DATETIME ((DATETIME) 0)
}
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="X86"
name="Microsoft.Windows.CAlfrescoApp"
type="win32"
/>
<description>Your app description here</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

View File

@@ -0,0 +1,13 @@
//
// CAlfrescoApp.RC2 - resources Microsoft Visual C++ does not edit directly
//
#ifdef APSTUDIO_INVOKED
#error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
// Add manually edited resources here...
/////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,25 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by CAlfrescoApp.rc
//
#define IDM_ABOUTBOX 0x0010
#define IDD_ABOUTBOX 100
#define IDS_ABOUTBOX 101
#define IDD_CALFRESCOAPP_DIALOG 102
#define IDR_HTML_CALFRESCOAPP_DIALOG 104
#define IDI_ICON1 133
#define IDD_DIALOG1 134
#define IDD_FILESTATUS 134
#define IDC_MSGTEXT 1001
#define IDC_FILELIST 1002
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 135
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1005
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,420 @@
#include <iostream>
#include "alfresco\Alfresco.hpp"
#include "util\String.h"
#include "util\DataBuffer.h"
#include "util\FileName.h"
#include <shellapi.h>
using namespace std;
using namespace JLAN;
// Function prototypes
bool doFolderStatus( Alfresco& alfresco, const wchar_t* fileSpec = L"*.*");
bool doCheckInOut( Alfresco& alfresco, StringList& files);
bool doCheckIn( Alfresco& alfresco, PTR_AlfrescoFileInfo& fileInfo);
bool doCheckOut( Alfresco& alfresco, PTR_AlfrescoFileInfo& fileInfo);
/**
* Alfresco Windows Drag And Drop Application
*
* @author GKSpencer
*/
int wmain( int argc, wchar_t* argv[], wchar_t* envp[]) {
// Output a startup banner
wcout << L"Alfresco Drag And Drop Application" << endl;
wcout << L"----------------------------------" << endl;
// Check if the app is running from a network drive
String appPath(argv[0]);
// String appPath("\\\\StarlaA\\Alfresco\\Garys Space\\AlfrescoApp.exe");
// String appPath("Z:\\Garys Space\\AlfrescoApp.exe");
// argc = 2;
// Looks like a UNC path, trim off the application name
int pos = appPath.lastIndexOf(PathSeperator);
if ( pos < 0) {
wcout << L"%% Invalid application path, " << appPath << endl;
return 1;
}
// Get the path to the folder containing the application
String folderPath = appPath.substring(0, pos);
// Create the Alfresco interface
Alfresco alfresco(folderPath);
if ( alfresco.isAlfrescoFolder()) {
// If there are no file paths on the command line then display a status page for the files
// in the Alfresco folder
if ( argc == 1) {
// Display status for the files in the Alfresco folder
doFolderStatus( alfresco);
}
else {
// Build a list of the file names
StringList fileList;
for ( int i = 1; i < argc; i++)
fileList.addString( String(argv[i]));
// fileList.addString(L"N:\\testArea\\msword\\CIFSLOG.doc");
// fileList.addString(L"\\\\StarlaA\\Alfresco\\Garys Space\\CIFSLOG.doc");
// Process the file list and check in or out each file
doCheckInOut( alfresco, fileList);
}
}
else {
wcout << L"%% Not a valid Alfresco CIFS folder, " << folderPath << endl;
return 1;
}
// Wait for user input
wcout << L"Press <Enter> to continue ..." << flush;
getchar();
}
/**
* Display file status of the files in the target Alfresco folder
*
* @param Alfresco& alfresco
* @param const wchar_t* fileSpec
* @return bool
*/
bool doFolderStatus( Alfresco& alfresco, const wchar_t* fileSpec) {
// Get the base UNC path
String uncPath = alfresco.getUNCPath();
uncPath.append(PathSeperator);
// Search the Alfresco folder
WIN32_FIND_DATA findData;
String searchPath = uncPath;
searchPath.append( fileSpec);
bool sts = false;
HANDLE fHandle = FindFirstFile( searchPath, &findData);
if ( fHandle != INVALID_HANDLE_VALUE) {
// Loop until all files have been returned
PTR_AlfrescoFileInfo pFileInfo;
sts = true;
while ( fHandle != INVALID_HANDLE_VALUE) {
// Get the file name, ignore the '.' and '..' files
String fName = findData.cFileName;
if ( fName.equals(L".") || fName.equals(L"..")) {
// Get the next file/folder name in the search
if ( FindNextFile( fHandle, &findData) == 0)
fHandle = INVALID_HANDLE_VALUE;
continue;
}
// Get the file information for the current file folder
pFileInfo = alfresco.getFileInformation( findData.cFileName);
if ( pFileInfo.get() != NULL) {
// Output the file details
wcout << pFileInfo->getName() << endl;
if ( pFileInfo->isType() == TypeFolder)
wcout << L" [Folder]" << endl;
if ( pFileInfo->isWorkingCopy())
wcout << L" [Work: " << pFileInfo->getCopyOwner() << L", " << pFileInfo->getCopiedFrom() << L"]" << endl;
if ( pFileInfo->getLockType() != LockNone)
wcout << L" [Lock: " << (pFileInfo->getLockType() == LockRead ? L"READ" : L"WRITE") << L", " <<
pFileInfo->getLockOwner() << L"]" << endl;
if ( pFileInfo->hasContent())
wcout << L" [Content: " << pFileInfo->getContentLength() << L", " << pFileInfo->getContentType() << L"]" << endl;;
// Get the next file/folder name in the search
if ( FindNextFile( fHandle, &findData) == 0)
fHandle = INVALID_HANDLE_VALUE;
}
else {
sts = false;
fHandle = INVALID_HANDLE_VALUE;
}
}
}
// Return status
return sts;
}
/**
* Process the list of files and check in or out each file
*
* @param alfresco Alfresco&
* @param files StringList&
*/
bool doCheckInOut( Alfresco& alfresco, StringList& files) {
// Process the list of files and either check in the file if it is a working copy or check out
// the file
for ( unsigned int i = 0; i < files.numberOfStrings(); i++) {
// Get the current file name
String curFile = files.getStringAt( i);
// Check if the path is on an Alfresco mapped drive
if ( alfresco.isMappedDrive() && curFile.startsWithIgnoreCase( alfresco.getDrivePath())) {
// Convert the path to a UNC path
String uncPath = alfresco.getRootPath();
uncPath.append( curFile.substring(2));
curFile = uncPath;
}
// Check that the path is to a file
bool copyFile = false;
DWORD attr = GetFileAttributes( curFile);
if ( attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
// Get the file name from the path
StringList nameParts = FileName::splitPath( curFile);
String curName = nameParts.getStringAt( 1);
// Get the Alfresco file status information
PTR_AlfrescoFileInfo pFileInfo = alfresco.getFileInformation( curName);
// If the path is to a file that is not on the Alfresco share the file will need to be copied,
// after checking the status of a matching file in the Alfresco folder
if ( curFile.length() >= 3 && curFile.substring(1,3).equals( L":\\")) {
// Check if there is an existing file with the same name
if ( pFileInfo.get() != NULL) {
// Check if the file is a working copy
if ( pFileInfo->isWorkingCopy()) {
// Local file matches a working copy file in the Alfresco folder
wcout << L"Found matching working copy for local file " << curName << endl;
}
else if ( pFileInfo->getLockType() != LockNone) {
// File is locked, may be the original document
wcout << L"%% Destination file " << curName << L" is locked" << endl;
return false;
}
else {
// Indicate that we have copied a new file to the Alfresco share, do not check in/out
copyFile = true;
}
}
else {
// Indicate that we have copied a new file to the Alfresco share, do not check in/out
copyFile = true;
}
// Build the from/to paths, must be double null terminated
wchar_t fromPath[MAX_PATH + 1];
wchar_t toPath[MAX_PATH + 1];
memset( fromPath, 0, sizeof( fromPath));
memset( toPath, 0, sizeof( toPath));
wcscpy( fromPath, curFile.data());
wcscpy( toPath, alfresco.getUNCPath());
// Copy the local file to the Alfresco folder
SHFILEOPSTRUCT fileOpStruct;
memset( &fileOpStruct, 0, sizeof(SHFILEOPSTRUCT));
fileOpStruct.hwnd = HWND_DESKTOP;
fileOpStruct.wFunc = FO_COPY;
fileOpStruct.pFrom = fromPath;
fileOpStruct.pTo = toPath;
fileOpStruct.fFlags= 0;
fileOpStruct.fAnyOperationsAborted =false;
// Copy the file to the Alfresco folder
if ( SHFileOperation( &fileOpStruct) != 0) {
// File copy failed
wcout << L"%% Failed to copy file " << curFile << endl;
return false;
}
else if ( fileOpStruct.fAnyOperationsAborted) {
// User aborted the file copy
wcout << L"%% Copy aborted for " << curFile << endl;
return false;
}
// Get the file information for the copied file
pFileInfo = alfresco.getFileInformation( curName);
}
// Check in or check out the file
if ( pFileInfo.get() != NULL) {
// Check if the file should be checked in/out
if ( copyFile == false) {
// Check if the file is a working copy, if so then check it in
if ( pFileInfo->isWorkingCopy()) {
// Check in the file
doCheckIn( alfresco, pFileInfo);
}
else if ( pFileInfo->getLockType() == LockNone) {
// Check out the file
doCheckOut( alfresco, pFileInfo);
}
else {
// File is locked, may already be checked out
wcout << L"%% File " << curFile << L" is locked" << endl;
}
}
else {
// No existing file to link the copied file to
wcout << L"Copied file " << curFile << L" to Alfresco share" << endl;
}
}
else
wcout << L"%% Failed to get file status for " << curFile << endl;
}
else
wcout << L"%% Path " << curFile << L" is a folder, ignored" << endl;
}
// Return status
return true;
}
/**
* Check in the specified file
*
* @param alfresco Alfresco&
* @param pFileInfo PTR_AlfrescoFileInfo&
* @return bool
*/
bool doCheckIn( Alfresco& alfresco, PTR_AlfrescoFileInfo& pFileInfo) {
bool checkedIn = false;
try {
// Check in the specified file
alfresco.checkIn( pFileInfo->getName());
wcout << L"Checked in file " << pFileInfo->getName() << endl;
// Indicate that the check in was successful
checkedIn = true;
}
catch (Exception ex) {
wcerr << L"%% Error checking in file " << pFileInfo->getName() << endl;
wcerr << L" " << ex.getMessage() << endl;
}
// Return the check in status
return checkedIn;
}
/**
* Check out the specified file
*
* @param alfresco Alfresco&
* @param pFileInfo PTR_AlfrescoFileInfo&
* @return bool
*/
bool doCheckOut( Alfresco& alfresco, PTR_AlfrescoFileInfo& pFileInfo) {
bool checkedOut = false;
try {
// Check out the specified file
String workingCopy;
alfresco.checkOut( pFileInfo->getName(), workingCopy);
wcout << L"Checked out file " << pFileInfo->getName() << " to " << workingCopy << endl;
// Indicate that the check out was successful
checkedOut = true;
}
catch (Exception ex) {
wcerr << L"%% Error checking out file " << pFileInfo->getName() << endl;
wcerr << L" " << ex.getMessage() << endl;
}
// Return the check out status
return checkedOut;
}

View File

@@ -0,0 +1,448 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "alfresco\Alfresco.hpp"
#include "util\DataBuffer.h"
#include "util\Exception.h"
#include "util\Integer.h"
#include <WinNetWk.h>
using namespace Alfresco;
using namespace std;
// Define exceptions
EXCEPTION_CLASS(Alfresco, BadInterfaceException);
/**
* Class constructor
*
* @param path UNC or mapped drive path to an Alfresco folder on CIFS server
*/
AlfrescoInterface::AlfrescoInterface(String& path) {
// Clear the file handle
m_handle = INVALID_HANDLE_VALUE;
// Check if the path is to a mapped drive
String alfPath = path;
if ( alfPath.length() >= 3 && alfPath.substring(1,3).equals( L":\\")) {
// Try and convert the local path to a UNC path
m_mappedDrive = alfPath.substring(0, 2);
wchar_t remPath[MAX_PATH];
DWORD remPathLen = MAX_PATH;
DWORD sts = WNetGetConnection(( LPWSTR) m_mappedDrive.data(), remPath, &remPathLen);
if ( sts != NO_ERROR)
return;
// Build the UNC path to the folder
alfPath = remPath;
if ( alfPath.endsWith( PathSeperator) == false)
alfPath.append( PathSeperator);
if ( path.length() > 3)
alfPath.append( path.substring( 3));
}
// Save the UNC path
m_uncPath = alfPath;
// Check if the UNC path is valid
if ( m_uncPath.startsWith(UNCPathPrefix)) {
// Strip any trailing separator from the path
if ( m_uncPath.endsWith(PathSeperator))
m_uncPath = m_uncPath.substring(0, m_uncPath.length() - 1);
// Make sure the path is to a folder
DWORD attr = GetFileAttributes(m_uncPath);
if ( attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
// Open the path
m_handle = CreateFile(m_uncPath, FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
}
// Set the root path
int pos = m_uncPath.indexOf( PathSeperator, 2);
if ( pos != -1) {
pos = m_uncPath.indexOf( PathSeperator, pos + 1);
if ( pos == -1)
m_rootPath = m_uncPath;
else
m_rootPath = m_uncPath.substring(0, pos);
}
}
}
/**
* Class destructor
*/
AlfrescoInterface::~AlfrescoInterface() {
// Close the folder
if ( m_handle != INVALID_HANDLE_VALUE)
CloseHandle(m_handle);
}
/**
* Check if the path is a folder on an Alfresco CIFS server
*
* @return bool
*/
bool AlfrescoInterface::isAlfrescoFolder( void) {
// Check if the handle is valid, if not then the path is not valid
if ( m_handle == INVALID_HANDLE_VALUE)
return false;
// Send a special I/O control to the Alfresco share to check that it is an Alfresco CIFS server
DataBuffer reqbuf(16);
DataBuffer respbuf(256);
reqbuf.putFixedString(IOSignature, IOSignatureLen);
bool alfFolder = false;
try {
sendIOControl( FSCTL_ALFRESCO_PROBE, reqbuf, respbuf);
alfFolder = true;
}
catch ( Exception ex) {
}
// If the folder is not an Alfresco CIFS folder then close the folder
if ( alfFolder == false) {
CloseHandle(m_handle);
m_handle = INVALID_HANDLE_VALUE;
}
// Return the folder status
return alfFolder;
}
/**
* Return Alfresco file information for the specified file/folder
*
* @param fileName const wchar_t*
* @return PTR_AlfrescoFileInfo
*/
PTR_AlfrescoFileInfo AlfrescoInterface::getFileInformation( const wchar_t* fileName) {
// Check if the folder handle is valid
if ( m_handle == INVALID_HANDLE_VALUE)
throw BadInterfaceException();
// Build the file information I/O control request
DataBuffer reqbuf( 256);
DataBuffer respbuf( 512);
reqbuf.putFixedString( IOSignature, IOSignatureLen);
reqbuf.putString( fileName);
sendIOControl( FSCTL_ALFRESCO_FILESTS, reqbuf, respbuf);
// Unpack the request status
PTR_AlfrescoFileInfo pFileInfo;
unsigned int reqSts = respbuf.getInt();
if ( reqSts == StsSuccess) {
// Create the file information
pFileInfo.reset( new AlfrescoFileInfo( fileName));
// Unpack the file details
pFileInfo->setType( respbuf.getInt());
if ( pFileInfo->isType() == TypeFile) {
// Unpack the working copy details
if ( respbuf.getInt() == True) {
String workOwner = respbuf.getString();
String workFrom = respbuf.getString();
pFileInfo->setWorkingCopy( workOwner, workFrom);
}
// Unpack the lock details
unsigned int lockType = respbuf.getInt();
String lockOwner;
if ( lockType != LockNone)
lockOwner = respbuf.getString();
pFileInfo->setLockType( lockType, lockOwner);
// Unpack the content details
if ( respbuf.getInt() == True) {
LONG64 siz = respbuf.getLong();
String mimeType = respbuf.getString();
pFileInfo->setContent( siz, mimeType);
}
}
}
// Return the file information
return pFileInfo;
}
/**
* Check in a working copy file
*
* @param fileName const wchar_t*
* @param keepCheckedOut bool
*/
void AlfrescoInterface::checkIn( const wchar_t* fileName, bool keepCheckedOut) {
// Check if the folder handle is valid
if ( m_handle == INVALID_HANDLE_VALUE)
throw BadInterfaceException();
// Build the file information I/O control request
DataBuffer reqbuf( 256);
DataBuffer respbuf( 128);
reqbuf.putFixedString( IOSignature, IOSignatureLen);
reqbuf.putString( fileName);
reqbuf.putInt( keepCheckedOut ? True : False);
sendIOControl( FSCTL_ALFRESCO_CHECKIN, reqbuf, respbuf);
// Get the status code
unsigned int stsCode = respbuf.getInt();
if ( stsCode == StsSuccess)
return;
else {
// Get the error message, if available
String errMsg;
if ( respbuf.getAvailableLength() > 0)
errMsg = respbuf.getString();
else {
errMsg = "Error code ";
errMsg.append( Integer::toString( stsCode));
}
// Throw an exception
throw Exception( errMsg);
}
}
/**
* Check out a file and return the working copy file name
*
* @param fileName const wchar_t*
* @param workingCopy String&
*/
void AlfrescoInterface::checkOut( const wchar_t* fileName, String& workingCopy) {
// Check if the folder handle is valid
if ( m_handle == INVALID_HANDLE_VALUE)
throw BadInterfaceException();
// Build the file information I/O control request
DataBuffer reqbuf( 256);
DataBuffer respbuf( 256);
reqbuf.putFixedString( IOSignature, IOSignatureLen);
reqbuf.putString( fileName);
sendIOControl( FSCTL_ALFRESCO_CHECKOUT, reqbuf, respbuf);
// Get the status code
unsigned int stsCode = respbuf.getInt();
if ( stsCode == StsSuccess) {
// Get the working copy file name
workingCopy = respbuf.getString();
}
else {
// Get the error message, if available
String errMsg;
if ( respbuf.getAvailableLength() > 0)
errMsg = respbuf.getString();
else {
errMsg = "Error code ";
errMsg.append( Integer::toString( stsCode));
}
// Throw an exception
throw Exception( errMsg);
}
}
/**
* Send an I/O control request to the Alfresco CIFS server, receive and validate the response
*
* @param ctlCode const unsigned int
* @param reqbuf DataBuffer&
* @param respbuf DataBuffer&
*/
void AlfrescoInterface::sendIOControl( const unsigned int ctlCode, DataBuffer& reqbuf, DataBuffer& respbuf) {
// Send the I/O control request, receive the response
DWORD retLen = 0;
BOOL res = DeviceIoControl( m_handle, ctlCode, reqbuf.getBuffer(), reqbuf.getLength(),
respbuf.getBuffer(), respbuf.getBufferLength(), &retLen, (LPOVERLAPPED) NULL);
if ( res) {
// Validate the reply signature
if ( retLen >= IOSignatureLen) {
respbuf.setLength(retLen);
respbuf.setEndOfBuffer();
String sig = respbuf.getString(IOSignatureLen, false);
if ( sig.equals(IOSignature) == false)
throw Exception( L"Invalid I/O control signature received");
}
}
else
throw Exception( L"Send I/O control error", Integer::toString( GetLastError()));
}
/**
* Class constructor
*
* @param fileName const wchar_t*
*/
AlfrescoFileInfo::AlfrescoFileInfo(const wchar_t* fileName) {
m_name = fileName;
m_workingCopy = false;
m_lockType = LockNone;
m_hasContent = false;
m_contentLen = 0L;
}
/**
* Set the working copy owner and copied from document path
*
* @param owner const wchar_t*
* @param copiedFrom const wchar_t*
*/
void AlfrescoFileInfo::setWorkingCopy( const wchar_t* owner, const wchar_t* copiedFrom) {
m_workingCopy = false;
m_workOwner = L"";
m_copiedFrom = L"";
if ( owner != NULL) {
m_workingCopy = true;
m_workOwner = owner;
if ( copiedFrom != NULL)
m_copiedFrom = copiedFrom;
}
}
/**
* Set the lock type and owner
*
* @param typ unsigned int
* @param owner const wchar_t*
*/
void AlfrescoFileInfo::setLockType( unsigned int typ, const wchar_t* owner) {
m_lockType = typ;
m_lockOwner = owner;
}
/**
* Set the lock type and owner
*
* @param siz LONG64
* @param mimeType const wchar_t*
*/
void AlfrescoFileInfo::setContent( LONG64 siz, const wchar_t* mimeType) {
m_hasContent = true;
m_contentLen = siz;
m_contentMimeType = mimeType;
}
/**
* Equality operator
*
* @return bool
*/
bool AlfrescoFileInfo::operator==( const AlfrescoFileInfo& finfo) {
if ( getName().equals( finfo.getName()))
return true;
return false;
}
/**
* Less than operator
*
* @return bool
*/
bool AlfrescoFileInfo::operator<( const AlfrescoFileInfo& finfo) {
if ( finfo.getName().compareTo( getName()) < 0)
return true;
return false;
}

View File

@@ -0,0 +1,232 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "util\ByteArray.h"
#include <memory.h>
using namespace Alfresco;
/**
* Class constructor
*
* @param len BUFLEN
* @param clearMem bool
*/
ByteArray::ByteArray( BUFLEN len, bool clearMem) {
// Allocate a byte array of the specified size
if ( len > 0) {
m_data = new unsigned char[ len];
if ( clearMem)
memset( m_data, 0, len);
}
else
m_data = NULL;
m_length = len;
}
/**
* Class constructor
*
* @param data CBUFPTR
* @param len BUFLEN
*/
ByteArray::ByteArray( CBUFPTR data, BUFLEN len) {
m_data = NULL;
m_length = 0;
setData( data, len);
}
/**
* Class constructor
*
* @param data const char*
* @param len BUFLEN
*/
ByteArray::ByteArray( const char* data, BUFLEN len) {
m_data = NULL;
m_length = 0;
setData(( CBUFPTR) data, len);
}
/**
* Copy constructor
*
* @param byts const ByteArray&
*/
ByteArray::ByteArray( const ByteArray& byts) {
m_data = NULL;
m_length = 0;
setData( byts.getData(), byts.getLength());
}
/**
* Class destructor
*
* @return
*/
ByteArray::~ByteArray() {
if ( m_data != NULL)
delete[] m_data;
}
/**
* Subscript operator
*
* @param idx const unsigned int
* @return unsigned char&
*/
unsigned char& ByteArray::operator [](const unsigned int idx) {
return m_data[ idx];
}
/**
* Assignment operator
*
* @param byts const ByteArray&
* @return ByteArray&
*/
ByteArray& ByteArray::operator = (const ByteArray& byts) {
if ( byts.getLength() > 0)
setData( byts.getData(), byts.getLength());
else
m_length = 0;
return *this;
}
/**
* Assignment operator
*
* @param byts std::string&
* @return ByteArray&
*/
ByteArray& ByteArray::operator = ( std::string& byts) {
if ( byts.length() > 0)
setData(( CBUFPTR) byts.data(), ( BUFLEN) byts.length());
else
m_length = 0;
return *this;
}
/**
* Equality operator
*
* @param byts const ByteArray&
* @return bool
*/
bool ByteArray::operator== ( const ByteArray& byts) {
// Check if the arrays are the same length
if ( getLength() != byts.getLength())
return false;
// Check if the array is empty
if (getLength() == 0)
return true;
// Check if the array bytes are equal
if ( memcmp( getData(), byts.getData(), getLength()) == 0)
return true;
return false;
}
/**
* Set the array length, and optionally clear the memory
*
* @param len BUFLEN
* @param clearMem bool
*/
void ByteArray::setLength( BUFLEN len, bool clearMem) {
// Check if the current block is the correct length
if ( m_length != len) {
// Delete the current array
if ( m_data != NULL)
delete[] m_data;
// Allocate the new array
if ( len > 0)
m_data = new unsigned char[len];
else
m_data = NULL;
m_length = len;
}
// Check if the memory should be cleared
if ( clearMem && m_data != NULL)
memset( m_data, 0, m_length);
}
/**
* Set the data and length
*
* @param data CBUFPTR
* @param len BUFLEN
*/
void ByteArray::setData( CBUFPTR data, BUFLEN len) {
// Delete the existing data
if ( m_data != NULL)
delete[] m_data;
// Allocate a byte array of the specified size
if ( data != NULL && len > 0) {
// Allocate a buffer and copy the data
m_data = new unsigned char[ len];
memcpy( m_data, data, len);
}
else
m_data = NULL;
m_length = len;
}
/**
* Set a byte value
*
* @param idx unsigned int
* @param val unsigned char
*/
void ByteArray::setByte( unsigned int idx, unsigned char val) {
if ( idx < getLength())
m_data[idx] = val;
}

View File

@@ -0,0 +1,732 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "util\DataBuffer.h"
#include "util\Exception.h"
using namespace Alfresco;
using namespace std;
// Use a macro for buffer overflow checks
#define CHECK_BUFFER(sz) {if ((( m_buflen + m_offset) - m_pos) < sz) throw ArrayIndexOutOfBoundsException(__FILE__, __LINE__, L"DataBuffer overflow"); }
#define CHECK_BUFFER_POS(pos,sz) {if ((( m_buflen + m_offset) - pos) < sz) throw ArrayIndexOutOfBoundsException(__FILE__, __LINE__, L"DataBuffer overflow"); }
#define EXTEND_CHECK(sz) {if ((( m_buflen + m_offset) - m_pos) < sz) extendBuffer(); }
#define EXTEND_CHECK_POS(pos,sz) {if ((( m_buflen + m_offset) - pos) < sz) extendBuffer(); }
/**
* Class constructor
*
* @param siz unsigned int
*/
DataBuffer::DataBuffer( unsigned int siz) {
m_buf = new unsigned char[siz];
m_buflen = siz;
m_owner = true;
m_pos = 0;
m_endpos = 0;
m_offset = 0;
}
/**
* Class constructor
*
* @param buf BUFPTR
* @param off BUFPOS
* @param len BUFLEN
*/
DataBuffer::DataBuffer( BUFPTR buf, BUFPOS off, BUFLEN len) {
m_buf = buf;
m_buflen = len;
m_owner = false;
m_pos = off;
m_offset = off;
m_endpos = off + len;
}
/**
* Class destructor
*/
DataBuffer::~DataBuffer() {
// Delete the buffer, if owned by this object
if ( m_owner == true && m_buf != NULL)
delete[] m_buf;
}
/**
* Return the buffer length
*
* @return BUFLEN
*/
BUFLEN DataBuffer::getLength( void) const {
if ( m_endpos != 0)
return m_endpos - m_offset;
return m_pos - m_offset;
}
/**
* Return the length in words
*
* @return unsigned int
*/
unsigned int DataBuffer::getLengthInWords( void) const {
return getLength() / 2;
}
/**
* Return the available buffer length
*
* @return BUFLEN
*/
BUFLEN DataBuffer::getAvailableLength( void) const {
if ( m_endpos == 0)
return 0;
return m_endpos - m_pos;
}
/**
* Get a byte from the buffer and advance the buffer pointer
*
* @return unsigned char
*/
unsigned char DataBuffer::getByte( void) {
// Check if there is enough space in the buffer for the data
CHECK_BUFFER(1);
// Return the data
return (unsigned int) m_buf[m_pos++];
}
/**
* Get a short/16bit value from the buffer and advance the buffer pointer
*
* @return unsigned int
*/
unsigned int DataBuffer::getShort( void) {
// Check if there is enough space in the buffer for the data
CHECK_BUFFER(2);
// Get a short value from the buffer
unsigned int sval = DataPacker::getIntelShort( m_buf, m_pos);
m_pos += 2;
return sval;
}
/**
* Get an integer from the buffer and advance the buffer pointer
*
* @return unsigned int
*/
unsigned int DataBuffer::getInt( void) {
// Check if there is enough space in the buffer for the data
CHECK_BUFFER(4);
// Get a short value from the buffer
unsigned int ival = DataPacker::getIntelInt( m_buf, m_pos);
m_pos += 4;
return ival;
}
/**
* Get a long from the buffer and advance the buffer pointer
*
* @return LONG64
*/
LONG64 DataBuffer::getLong( void) {
// Check if there is enough space in the buffer for the data
CHECK_BUFFER(8);
// Get a long value from the buffer
LONG64 lval = DataPacker::getIntelLong( m_buf, m_pos);
m_pos += 8;
return lval;
}
/**
* Get a string from the buffer and advance the buffer pointer
*
* @param uni bool
* @return String
*/
String DataBuffer::getString( bool uni) {
return getString( 255, uni);
}
/**
* Get a string from the buffer and advance the buffer pointer
*
* @param maxlen unsigned int
* @param uni bool
* @return String
*/
String DataBuffer::getString( unsigned int maxlen, bool uni) {
// Check for Unicode or ASCII
String ret;
unsigned int availLen = 0;
if ( uni) {
// Word align the current buffer position, calculate the available length
m_pos = DataPacker::wordAlign(m_pos);
availLen = (m_endpos - m_pos) / 2;
if ( availLen < maxlen)
maxlen = availLen;
ret = DataPacker::getUnicodeString(m_buf, m_pos, maxlen);
if ( ret.length() < maxlen)
m_pos += (ret.length() * 2) + 2;
else
m_pos += maxlen * 2;
}
else {
// Calculate the available length
availLen = m_endpos - m_pos;
if ( availLen < maxlen)
maxlen = availLen;
// Unpack the ASCII string
ret = DataPacker::getString(m_buf, m_pos, maxlen);
if ( ret.length() < maxlen)
m_pos += ret.length() + 1;
else
m_pos += maxlen;
}
// Return the string
return ret;
}
/**
* Get a short value at the specified buffer position
*
* @param idx unsigned int
* @return unsigned int
*/
unsigned int DataBuffer::getShortAt( unsigned int idx) {
// Check if there is enough data in the buffer
BUFPOS pos = m_offset + (idx * 2);
CHECK_BUFFER_POS(pos, 2);
// Unpack the short value
return DataPacker::getIntelShort(m_buf, pos);
}
/**
* Get an integer value at the specified buffer position
*
* @param idx unsigned int
* @return unsigned int
*/
unsigned int DataBuffer::getIntAt( unsigned int idx) {
// Check if there is enough data in the buffer
BUFPOS pos = m_offset + (idx * 4);
CHECK_BUFFER_POS(pos, 4);
// Unpack the integer value
return DataPacker::getIntelInt(m_buf, pos);
}
/**
* Get a long value at the specified buffer position
*
* @param idx unsigned int
* @return LONG64
*/
LONG64 DataBuffer::getLongAt( unsigned int idx) {
// Check if there is enough data in the buffer
BUFPOS pos = m_offset + (idx * 8);
CHECK_BUFFER_POS(pos, 8);
// Unpack the long value
return DataPacker::getIntelLong(m_buf, pos);
}
/**
* Append a byte to the buffer and advance the buffer pointer
*
* @param byt unsigned char
*/
void DataBuffer::putByte( unsigned char byt) {
// Check if the buffer needs extending
EXTEND_CHECK(1);
// Pack the data, update the buffer pointer
m_buf[m_pos++] = byt;
}
/**
* Append a short to the buffer and advance the buffer pointer
*
* @param sval unsigned int
*/
void DataBuffer::putShort( unsigned int sval) {
// Check if the buffer needs extending
EXTEND_CHECK(2);
// Pack the data, update the buffer pointer
DataPacker::putIntelShort( sval, m_buf, m_pos);
m_pos += 2;
}
/**
* Append an integer to the buffer and advance the buffer pointer
*
* @param ival unsigned int
*/
void DataBuffer::putInt( unsigned int ival) {
// Check if the buffer needs extending
EXTEND_CHECK(4);
// Pack the data, update the buffer pointer
DataPacker::putIntelInt( ival, m_buf, m_pos);
m_pos += 4;
}
/**
* Append a long to the buffer and advance the buffer pointer
*
* @param lval LONG64
*/
void DataBuffer::putLong( LONG64 lval) {
// Check if the buffer needs extending
EXTEND_CHECK(8);
// Pack the data, update the buffer pointer
DataPacker::putIntelLong( lval, m_buf, m_pos);
m_pos += 8;
}
/**
* Put a short value into the buffer at the specified position
*
* @param idx unsigned int
* @param sval unsigned int
*/
void DataBuffer::putShortAt( unsigned int idx, unsigned int sval) {
// Check if there is enough space in the buffer
BUFPOS pos = m_offset + (idx * 2);
EXTEND_CHECK_POS(pos,2);
// Pack the short value
DataPacker::putIntelShort(sval, m_buf, pos);
}
/**
* Put an integer value into the buffer at the specified position
*
* @param idx unsigned int
* @param ival unsigned int
*/
void DataBuffer::putIntAt( unsigned int idx, unsigned int ival) {
// Check if there is enough space in the buffer
BUFPOS pos = m_offset + (idx * 4);
EXTEND_CHECK_POS(pos,4);
// Pack the integer value
DataPacker::putIntelInt(ival, m_buf, pos);
}
/**
* Put a long value into the buffer at the specified position
*
* @param idx unsigned int
* @param lval LONG64
*/
void DataBuffer::putLongAt( unsigned int idx, LONG64 lval) {
// Check if there is enough space in the buffer
BUFPOS pos = m_offset + (idx * 8);
EXTEND_CHECK_POS(pos,8);
// Pack the long value
DataPacker::putIntelLong(lval, m_buf, pos);
}
/**
* Append a string to the buffer and advance the buffer pointer
*
* @param str const String&
* @param uni bool
* @param nulTerm bool
*/
void DataBuffer::putString( const String& str, bool uni, bool nulTerm) {
// Check for Unicode or ASCII
if ( uni) {
// Check if there is enough space in the buffer
unsigned int bytLen = str.length() * 2;
if ( m_buflen - m_pos < bytLen)
extendBuffer(bytLen + 4);
// Word align the buffer position, pack the Unicode string
m_pos = DataPacker::wordAlign(m_pos);
DataPacker::putString(str, m_buf, m_pos, nulTerm, true);
m_pos += (str.length() * 2);
if ( nulTerm)
m_pos += 2;
}
else {
// Check if there is enough space in the buffer
if ( m_buflen - m_pos < str.length())
extendBuffer(str.length() + 2);
// Pack the ASCII string
DataPacker::putString(str, m_buf, m_pos, nulTerm);
m_pos += str.length();
if ( nulTerm)
m_pos++;
}
}
/**
* Append a fixed length string to the buffer and advance the buffer pointer
*
* @param str const String&
* @param len unsigned int
*/
void DataBuffer::putFixedString( const String& str, unsigned int len) {
// Check if there is enough space in the buffer
if ( m_buflen - m_pos < str.length())
extendBuffer(str.length() + 2);
// Pack the ASCII string
DataPacker::putString(str, m_buf, m_pos);
m_pos += len;
// Pad the string to the required length
while ( len > str.length()) {
m_buf[m_pos++] = 0;
len--;
}
}
/**
* Put a string into the buffer at the specified position
*
* @param str const String&
* @param pos BUFPOS
* @param uni bool
* @param nulTerm bool
* @return BUFPOS
*/
BUFPOS DataBuffer::putStringAt( const String& str, BUFPOS pos, bool uni, bool nulTerm) {
// Check for Unicode or ASCII
BUFPOS retPos = 0;
if ( uni) {
// Check if there is enough space in the buffer
unsigned int bytLen = str.length() * 2;
if ( m_buflen - pos < bytLen)
extendBuffer(bytLen + 4);
// Word align the buffer position, pack the Unicode string
pos = DataPacker::wordAlign(pos);
retPos = DataPacker::putString(str, m_buf, pos, nulTerm);
}
else {
// Check if there is enough space in the buffer
if ( m_buflen - pos < str.length())
extendBuffer(str.length() + 2);
// Pack the ASCII string
retPos = DataPacker::putString(str, m_buf, pos, nulTerm);
}
// Return the end of string buffer position
return retPos;
}
/**
* Put a fixed length string into the buffer at the specified position
*
* @param str const String&
* @param len unsigned int
* @param pos BUFPOS
* @return BUFPOS
*/
BUFPOS DataBuffer::putFixedStringAt( const String& str, unsigned int len, BUFPOS pos) {
// Check if there is enough space in the buffer
if ( m_buflen - pos < str.length())
extendBuffer(str.length() + 2);
// Pack the ASCII string
pos = DataPacker::putString(str, m_buf, pos);
// Pad the string
while ( len > str.length()) {
m_buf[pos++] = 0;
len--;
}
// Return the end of string buffer position
return pos;
}
/**
* Put a string pointer into the buffer
*
* @param off unsigned int
*/
void DataBuffer::putStringPointer( unsigned int off) {
// Calculate the offset from the start of the data buffer to the string position
DataPacker::putIntelInt(off - m_offset, m_buf, m_pos);
m_pos += 4;
}
/**
* Append a block of nulls to the buffer and advance the buffer pointer
*
* @param cnt unsigned int
*/
void DataBuffer::putZeros( unsigned int cnt) {
// Check if there is enough space in the buffer
if ( m_buflen - m_pos < cnt)
extendBuffer(cnt);
// Pack the zero bytes
for ( unsigned int i = 0; i < cnt; i++)
m_buf[m_pos++] = 0;
}
/**
* Word align the buffer pointer
*
*/
void DataBuffer::wordAlign( void) {
m_pos = DataPacker::wordAlign(m_pos);
}
/**
* Longword align the buffer pointer
*
*/
void DataBuffer::longwordAlign( void) {
m_pos = DataPacker::longwordAlign(m_pos);
}
/**
* Append a block of byte data to the buffer and advance the buffer pointer
*
* @param buf BUFPTR
* @param off BUFPOS
* @param len BUFLEN
*/
void DataBuffer::appendData( BUFPTR buf, BUFPOS off, BUFLEN len) {
// Check if there is enough space in the buffer
if ( m_buflen - m_pos < len)
extendBuffer(len);
// Copy the data to the buffer and update the current write position
memcpy( m_buf + m_pos, buf + off, len);
m_pos += len;
}
/**
* Copy data to the user buffer and advance the buffer pointer
*
* @param buf BUFPTR
* @param pos BUFPOS
* @param cnt unsigned int
*/
unsigned int DataBuffer::copyData( BUFPTR buf, BUFPOS pos, unsigned int cnt) {
// Check if there is any more data to copy
if ( m_pos == m_endpos)
return 0;
// Calculate the amount of data to copy
unsigned int siz = m_endpos - m_pos;
if ( siz > cnt)
siz = cnt;
// Copy the data to the user buffer and update the current read position
memcpy( buf + pos, m_buf + m_pos, siz);
m_pos += siz;
// Return the amount of data copied
return siz;
}
/**
* Advance the buffer pointer by the specified amount
*
* @param len unsigned int
*/
void DataBuffer::skipBytes( unsigned int len) {
// Check if there is enough data in the buffer
CHECK_BUFFER(len);
// Skip bytes
m_pos += len;
}
/**
* Set the end of buffer position
*/
void DataBuffer::setEndOfBuffer( void) {
m_endpos = m_pos;
m_pos = m_offset;
}
/**
* Set the buffer length
*
* @param len BUFLEN
*/
void DataBuffer::setLength( BUFLEN len) {
m_pos = m_offset + len;
}
/**
* Extend the buffer by the specified amount by reallocating the buffer and copying the existing
* data to the new buffer
*
* @param ext BUFLEN
*/
void DataBuffer::extendBuffer( BUFLEN ext) {
// Create a new buffer of the required size
BUFLEN newlen = m_buflen + ext;
BUFPTR newBuf = new unsigned char[newlen];
// Copy the data from the current buffer to the new buffer
memcpy( newBuf, m_buf, m_buflen);
// Check if the previous buffer was owned by this object
if ( m_owner)
delete[] m_buf;
// Set the new buffer to be the main buffer
m_buf = newBuf;
m_buflen = newlen;
m_owner = true;
}
/**
* Extend the buffer doubling the current size by reallocating the buffer and copying the existing
* data to the new buffer
*
*/
void DataBuffer::extendBuffer( void) {
extendBuffer( m_buflen * 2);
}

View File

@@ -0,0 +1,436 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include <string>
#include "util\DataPacker.h"
#include "util\ByteArray.h"
using namespace Alfresco;
/**
* Unpack a short/16 bit value from the buffer.
*
* @param buf CBUFPTR
* @param pos BUFPOS
* @return int
*/
int DataPacker::getShort(CBUFPTR buf, BUFPOS pos) {
int sval = ( buf[pos] << 8) + buf[pos+1];
return sval;
}
/**
* Unpack an int/32 bit value from the buffer.
*
* @param buf CBUFPTR
* @param pos BUFPOS
* @return int
*/
int DataPacker::getInt(CBUFPTR buf, BUFPOS pos) {
int ival = (buf[pos] << 24) + (buf[pos+1] << 16) + (buf[pos+2] << 8) + buf[pos+3];
return ival;
}
/**
* Unpack a long/64 bit value from the buffer.
*
* @param buf CBUFPTR
* @param pos BUFPOS
* @return LONG64
*/
LONG64 DataPacker::getLong(CBUFPTR buf, BUFPOS pos) {
LONG64 lval = 0;
BUFPTR pLval = (BUFPTR) &lval;
for ( unsigned int i = 0; i < 8; i++) {
pLval[7 - i] = buf[pos + i];
}
return lval;
}
/**
* Unpack a short/16 bit value in Intel format from the buffer.
*
* @param buf CBUFPTR
* @param pos BUFPOS
* @return int
*/
int DataPacker::getIntelShort(CBUFPTR buf, BUFPOS pos) {
int sval = ( buf[pos+1] << 8) + buf[pos];
return sval;
}
/**
* Unpack an int/32 bit value in Intel format from the buffer.
*
* @param buf CBUFPTR
* @param pos BUFPOS
* @return int
*/
int DataPacker::getIntelInt(CBUFPTR buf, BUFPOS pos) {
int ival = (buf[pos+3] << 24) + (buf[pos+2] << 16) + (buf[pos+1] << 8) + buf[pos];
return ival;
}
/**
* Unpack a long/64 bit value in Intel format from the buffer.
*
* @param buf CBUFPTR
* @param pos BUFPOS
* @return LONG64
*/
LONG64 DataPacker::getIntelLong(CBUFPTR buf, BUFPOS pos) {
LONG64 lval = 0;
BUFPTR pLval = (BUFPTR) &lval;
for ( unsigned int i = 0; i < 8; i++) {
pLval[i] = buf[pos + i];
}
return lval;
}
/**
* Unpack a string from the buffer.
*
* @param buf CBUFPTR
* @param pos BUFPOS
* @param maxLen const unsigned int
* @param isUni const bool
* @return String
*/
String DataPacker::getString(CBUFPTR buf, BUFPOS pos, const unsigned int maxLen, const bool isUni) {
// Check for a Unicode string
if ( isUni)
return getUnicodeString( buf, pos, maxLen);
// Search for the trailing null
unsigned int maxpos = pos + maxLen;
unsigned int endpos = pos;
while (buf[endpos] != '\0' && endpos < maxpos)
endpos++;
return String((const char*) buf, pos, endpos - pos);
}
/**
* Unpack a Unicode string from the buffer.
*
* @param buf CBUFPTR
* @param pos BUFPOS
* @param maxLen const unsigned int
* @return String
*/
String DataPacker::getUnicodeString(CBUFPTR buf, BUFPOS pos, const unsigned int maxLen) {
// Check for an empty string
if ( maxLen == 0)
return String();
// Word align the position
pos = wordAlign( pos);
// Search for the trailing null
int maxpos = pos + (maxLen * 2);
int endpos = pos;
std::wstring str;
int cpos = 0;
wchar_t curChar;
do {
// Get a Unicode character from the buffer
curChar = (wchar_t) DataPacker::getIntelShort(buf, endpos);
// Add the character to the string
if ( curChar != 0)
str += curChar;
// Update the buffer pointer
endpos += 2;
} while (curChar != 0 && endpos < maxpos);
// Return the string
return String(str);
}
/**
* Pack a short/16 bit value into the buffer.
*
* @param val const int
* @param buf BUFPTR
* @param pos BUFPOS
*/
void DataPacker::putShort(const int val, BUFPTR buf, BUFPOS pos) {
buf[pos] = (unsigned char) (val >> 8) & 0xFF;
buf[pos+1] = (unsigned char) (val & 0xFF);
}
/**
* Pack an int/32 bit value into the buffer.
*
* @param val const int
* @param buf BUFPTR
* @param pos BUFPOS
*/
void DataPacker::putInt(const int val, BUFPTR buf, BUFPOS pos) {
buf[pos] = (unsigned char) (val >> 24) & 0xFF;
buf[pos+1] = (unsigned char) (val >> 16) & 0xFF;
buf[pos+2] = (unsigned char) (val >> 8) & 0xFF;
buf[pos+3] = (unsigned char) (val & 0xFF);
}
/**
* Pack a long/64 bit value into the buffer.
*
* @param val const LONG64
* @param buf BUFPTR
* @param pos BUFPOS
*/
void DataPacker::putLong(const LONG64 val, BUFPTR buf, BUFPOS pos) {
BUFPTR pLval = (BUFPTR) &val;
buf[pos] = pLval[7];
buf[pos+1] = pLval[6];
buf[pos+2] = pLval[5];
buf[pos+3] = pLval[4];
buf[pos+4] = pLval[3];
buf[pos+5] = pLval[2];
buf[pos+6] = pLval[1];
buf[pos+7] = pLval[0];
}
/**
* Pack a short/16 bit value in Intel format into the buffer.
*
* @param val const int
* @param buf BUFPTR
* @param pos BUFPOS
*/
void DataPacker::putIntelShort(const int val, BUFPTR buf, BUFPOS pos) {
buf[pos+1] = (unsigned char) (val >> 8) & 0xFF;
buf[pos] = (unsigned char) (val & 0xFF);
}
/**
* Pack an int/32 bit value in Intel format into the buffer.
*
* @param val const int
* @param buf BUFPTR
* @param pos BUFPOS
*/
void DataPacker::putIntelInt(const int val, BUFPTR buf, BUFPOS pos) {
buf[pos+3] = (unsigned char) (val >> 24) & 0xFF;
buf[pos+2] = (unsigned char) (val >> 16) & 0xFF;
buf[pos+1] = (unsigned char) (val >> 8) & 0xFF;
buf[pos] = (unsigned char) (val & 0xFF);
}
/**
* Pack a long/64 bit value in Intel format into the buffer.
*
* @param val const LONG64
* @param buf BUFPTR
* @param pos BUFPOS
*/
void DataPacker::putIntelLong(const LONG64 val, BUFPTR buf, BUFPOS pos) {
BUFPTR pLval = (BUFPTR) &val;
buf[pos+7] = pLval[7];
buf[pos+6] = pLval[6];
buf[pos+5] = pLval[5];
buf[pos+4] = pLval[4];
buf[pos+3] = pLval[3];
buf[pos+2] = pLval[2];
buf[pos+1] = pLval[1];
buf[pos] = pLval[0];
}
/**
* Pack a string into the buffer.
*
* @param str const String&
* @param buf BUFPTR
* @param pos BUFPOS
* @param nullTerm const bool
* @param isUni const bool
* @return int
*/
unsigned int DataPacker::putString(const String& str, BUFPTR buf, BUFPOS pos, const bool nullTerm, const bool isUni) {
// Check if the string should be packed as Unicode or ASCII
unsigned int newPos = pos;
if ( isUni == true) {
// Pack the characters
for ( unsigned int i = 0; i < str.length(); i++) {
wchar_t ch = str.charAt(i);
buf[newPos++] = (unsigned char) (ch & 0xFF);
buf[newPos++] = (unsigned char) (ch >> 8) & 0xFF;
}
// Add a null terminator, if required
if ( nullTerm == true) {
buf[newPos++] = '\0';
buf[newPos++] = '\0';
}
}
else {
// Get the string as ASCII characters
ByteArray byts = str.getBytes();
// Pack the characters
for ( unsigned int i = 0; i < str.length(); i++)
buf[newPos++] = byts[i];
// Add a null terminator, if required
if ( nullTerm == true)
buf[newPos++] = '\0';
}
// Return the new buffer position
return newPos;
}
/**
* Pack an ASCII string into the buffer
*
* @param str const char*
* @param buf BUFPTR
* @param pos BUFPOS
* @param nullTerm bool
* @return unsigned int
*/
unsigned int DataPacker::putString(const char* str, BUFLEN len, BUFPTR buf, BUFPOS pos, bool nullTerm) {
// Copy the ASCII string to the buffer
memcpy(buf + pos, str, len);
BUFPOS endPos = pos + len;
if ( nullTerm == true)
buf[endPos] = '\0';
// Return the new buffer position
return endPos;
}
/**
* Pack a Unicode string into the buffer
*
* @param str const wchar_t*
* @param buf BUFPTR
* @param pos BUFPOS
* @param nullTerm bool
* @return unsigned int
*/
unsigned int DataPacker::putString(const wchar_t* str, BUFLEN len, BUFPTR buf, BUFPOS pos, bool nullTerm) {
// Copy the Unicode string to the buffer
BUFLEN uniLen = len * 2;
BUFPOS endPos = pos + uniLen;
memcpy(buf + pos, str, uniLen);
if ( nullTerm == true) {
buf[pos + uniLen + 1] = '\0';
buf[pos + uniLen + 2] = '\0';
endPos += 2;
}
// Return the new buffer position
return endPos;
}
/**
* Pack a number of zero bytes into the buffer.
*
* @param buf BUFPTR
* @param pos BUFPOS
* @param count const unsigned int
*/
void DataPacker::putZeros(BUFPTR buf, BUFPOS pos, const unsigned int count) {
for (unsigned int i = 0; i < count; i++)
buf[pos + i] = (unsigned char) 0;
}
/**
* Determine the amount of buffer space required to pack the string with the specified settings.
*
* @param str const String&
* @param isUni const bool
* @param nulTerm const bool
* @return unsigned int
*/
unsigned int DataPacker::getStringLength(const String& str, const bool isUni, const bool nulTerm) {
int len = str.length();
if ( nulTerm == true)
len += 1;
if ( isUni == true)
len *= 2;
return len;
}
/**
* Calculate the buffer position after packing the string with the specified settings.
*
* @param pos BUFPOS
* @param str const String&
* @param isUni const bool
* @param nulTerm const bool
* @return unsigned int
*/
unsigned int DataPacker::getBufferPosition(BUFPOS pos, const String& str, const bool isUni, const bool nulTerm) {
unsigned int len = str.length();
if ( nulTerm == true)
len += 1;
if ( isUni == true)
len *= 2;
return pos + len;
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "util\Exception.h"
using namespace Alfresco;
using namespace std;
// Define standard Java-like exceptions
EXCEPTION_CLASS(Alfresco, IOException);
EXCEPTION_CLASS(Alfresco, NullPointerException);
EXCEPTION_CLASS(Alfresco, ArrayIndexOutOfBoundsException);
EXCEPTION_CLASS(Alfresco, NumberFormatException);
/**
* Class constructor
*
* @param moduleName const char*
* @param lineNum unsigned int
* @param msg const wchar_t*
* @param msg2 const wchar_t*
* @param msg3 const wchar_t*
* @param msg4 const wchar_t*
* @param msg5 const wchar_t*
*/
Exception::Exception( const char* moduleName, unsigned int lineNum, const wchar_t* msg, const wchar_t* msg2,
const wchar_t* msg3, const wchar_t* msg4, const wchar_t* msg5) {
// Prefix the message string with the module name and line number
m_msg = moduleName;
if ( lineNum != 0) {
m_msg += " (";
m_msg += lineNum;
m_msg += ")";
}
m_msg += ": ";
// Add the messages parts
if ( msg)
m_msg += msg;
if ( msg2) {
m_msg += " ";
m_msg += msg2;
}
if ( msg3) {
m_msg += " ";
m_msg += msg3;
}
if ( msg4) {
m_msg += " ";
m_msg += msg4;
}
if ( msg5) {
m_msg += " ";
m_msg += msg5;
}
}
/**
* Class constructor
*
* @param msg const wchar_t*
* @param msg2 const wchar_t*
* @param msg3 const wchar_t*
* @param msg4 const wchar_t*
* @param msg5 const wchar_t*
*/
Exception::Exception( const wchar_t* msg, const wchar_t* msg2, const wchar_t* msg3, const wchar_t* msg4, const wchar_t* msg5) {
if ( msg)
m_msg = msg;
if ( msg2) {
m_msg += " ";
m_msg += msg2;
}
if ( msg3) {
m_msg += " ";
m_msg += msg3;
}
if ( msg4) {
m_msg += " ";
m_msg += msg4;
}
if ( msg5) {
m_msg += " ";
m_msg += msg5;
}
}
/**
* Copy constructor
*
* @param ex const Exception&
*/
Exception::Exception( const Exception& ex) {
m_msg = ex.getMessage();
}
/**
* Class destructor
*
*/
Exception::~Exception() {
}

View File

@@ -0,0 +1,390 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "util\FileName.h"
using namespace Alfresco;
using namespace std;
// Declare the Dos separator and NTFS stream separator strings
String& Alfresco::FileName::DosSeperator = String("\\");
String& Alfresco::FileName::NTFSStreamSeperator = String(":");
wchar_t Alfresco::FileName::DOS_SEPERATOR = L'\\';
/**
* Build a path using the specified components
*
* @param dev const String&
* @param path const String&
* @param fileName const String&
* @param sep wchar_t
* @return const String
*/
const String FileName::buildPath( const String& dev, const String& path, const String& fileName, wchar_t sep) {
// Build the path string
String fullPath;
// Check for a device name
if ( dev.isNotEmpty()) {
// Add the device name
fullPath.append( dev);
// Check if the device name has a file separator
if ( dev.length() > 0 && dev.charAt( dev.length() - 1) != sep)
fullPath.append( sep);
}
// Check for a path
if ( path.isNotEmpty()) {
// Add the path
if (fullPath.length() > 0
&& (path.charAt(0) == sep || path.charAt(0) == DOS_SEPERATOR))
fullPath.append( path.substring(1));
else
fullPath.append( path);
// Add a trailing separator, if required
if (path.length() > 0
&& path.charAt(path.length() - 1) != sep
&& fileName.isNotEmpty())
fullPath.append(sep);
}
// Check for a file name
if (fileName.isNotEmpty()) {
// Add the file name
if ( fullPath.length() > 0 && ( fileName.charAt(0) == sep || fileName.charAt(0) == DOS_SEPERATOR))
fullPath.append( fileName.substring(1));
else
fullPath.append( fileName);
}
// Debug
// Debug.println ( "BuildPath: " + fullPath.toString ());
// Convert the file separator characters in the path if we are not using the normal
// DOS file separator character.
if (sep != DOS_SEPERATOR)
return convertSeperators( fullPath, sep);
return fullPath;
}
/**
* Check if a file name contains a stream name
*
* @param fileName const String&
* @return bool
*/
bool FileName::containsStreamName( const String& fileName) {
// Check if the path contains the stream name separator character
if ( fileName.indexOf( NTFSStreamSeperator) != -1)
return true;
return false;
}
/**
* Convert path separator characters
*
* @param path const String&
* @param sep wchar_t
* @return const String
*/
const String FileName::convertSeperators( const String& path, wchar_t sep) {
// Check if the path contains any DOS separators
if ( path.indexOf( DOS_SEPERATOR) == -1)
return path;
// Convert DOS path separators to the specified separator
String newPath;
unsigned int idx = 0;
while ( idx < path.length()) {
// Get the current character from the path and check if it is a DOS path
// separator character.
wchar_t ch = path.charAt(idx++);
if (ch == DOS_SEPERATOR)
newPath.append(sep);
else
newPath.append(ch);
}
// Return the new path string
return newPath;
}
/**
* Make a relative path
*
* @param basePath const String&
* @param fullPath const String&
* @return const String
*/
const String FileName::makeRelativePath( const String& basePath, const String& fullPath) {
// Check if the base path is the root path
if ( basePath.length() == 0 || basePath.equals( DosSeperator)) {
// Return the full path, strip any leading separator
if ( fullPath.length() > 0 && fullPath.charAt(0) == DOS_SEPERATOR)
return fullPath.substring(1);
return fullPath;
}
// Split the base and full paths into separate components
StringList baseNames = splitAllPaths(basePath);
StringList fullNames = splitAllPaths(fullPath);
// Check that the full path is actually within the base path tree
if ( baseNames.numberOfStrings() > 0 && fullNames.numberOfStrings() > 0 &&
baseNames.getStringAt(0).equalsIgnoreCase(fullNames.getStringAt(0)) == false)
return String();
// Match the path names
unsigned int idx = 0;
while ( idx < baseNames.numberOfStrings() && idx < fullNames.numberOfStrings() &&
baseNames.getStringAt(idx).equalsIgnoreCase(fullNames.getStringAt(idx)))
idx++;
// Build the relative path
String relPath(128);
while ( idx < fullNames.numberOfStrings()) {
relPath.append(fullNames.getStringAt(idx++));
if ( idx < fullNames.numberOfStrings())
relPath.append(DOS_SEPERATOR);
}
// Return the relative path
return relPath;
}
/**
* Map an input path to a real path
*
* @param base const String&
* @param path const String&
* @return const String
*/
const String FileName::mapPath(const String& base, const String& path) {
return String();
}
/**
* Normalize a path converting all directories to uppercase and keeping the file name as is
*
* @param path const String&
* @return const String
*/
const String FileName::normalizePath(const String& path) {
// Split the path into directories and file name, only uppercase the directories to normalize
// the path.
String normPath = path;
if ( path.length() > 3) {
// Split the path to separate the folders/file name
int pos = path.lastIndexOf( DOS_SEPERATOR);
if ( pos != -1) {
// Get the path and file name parts, normalize the path
String pathPart = path.substring(0, pos).toUpperCase();
String namePart = path.substring(pos);
// Rebuild the path string
normPath = pathPart;
normPath += namePart;
}
}
// Return the normalized path
return normPath;
}
/**
* Remove the file name from the path
*
* @param path const String&
* @return const String
*/
const String FileName::removeFileName(const String& path) {
// Find the last path separator
int pos = path.lastIndexOf(DOS_SEPERATOR);
if (pos != -1)
return path.substring(0, pos);
// Return an empty string, no path separators
return "";
}
/**
* Split the path into all the component directories and filename
*
* @param path const String&
* @return StringList
*/
StringList FileName::splitAllPaths(const String& path) {
// Check if the path is valid
StringList paths;
if ( path.length() == 0) {
paths.addString( path);
return paths;
}
// Split the path
return path.tokenize( DosSeperator);
}
/**
* Split the path into separate directory path and file name strings
*
* @param path const String&
* @param sep wchar_t
* @return StringList
*/
StringList FileName::splitPath( const String& path, wchar_t sep) {
// Create an array of strings to hold the path and file name strings
StringList pathList;
String path0, path1;
// Check if the path is valid
if ( path.length() > 0) {
// Check if the path has a trailing separator, if so then there is no
// file name.
int pos = path.lastIndexOf(sep);
if (pos == -1 || pos == (path.length() - 1)) {
// Set the path string in the returned string array
path0 = path;
}
else {
// Split the path into directory list and file name strings
path1 = path.substring(pos + 1);
if (pos == 0)
path0 = path.substring(0, pos + 1);
else
path0 = path.substring(0, pos);
}
}
// Set the path strings
pathList.addString( path0);
pathList.addString( path1);
// Return the path strings
return pathList;
}
/**
* Split a path string into directory path, file name and stream name components
*
* @param path const String&
* @return StringList
*/
StringList FileName::splitPathStream( const String& path) {
// Allocate the return list
StringList pathList;
// Split the path into directory path and file/stream name
pathList = FileName::splitPath(path, DOS_SEPERATOR);
if ( pathList[1].length() == 0)
return pathList;
// Split the file name into file and stream names
int pos = pathList[1].indexOf( NTFSStreamSeperator);
if ( pos != -1) {
// Split the file/stream name
pathList[2] = pathList[1].substring(pos);
pathList[1] = pathList[1].substring(0,pos);
}
// Return the path components list
return pathList;
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "util\Integer.h"
using namespace Alfresco;
/**
* Convert an integer value to a hexadecimal string
*
* @param ival const unsigned int
* @return String
*/
String Integer::toHexString( const unsigned int ival) {
char buf[32];
itoa(ival, buf, 16);
return String(buf);
}
/**
* Convert an buffer pointer to a hexadecimal string
*
* @param ptr BUFPTR
* @return String
*/
String Integer::toHexString( BUFPTR ptr) {
char buf[32];
sprintf( buf, "%p", ptr);
return String(buf);
}
/**
* Convert an integer to a string
*
* @param ival unsigned int
* @param radix unsigned int
* @return String
*/
String Integer::toString( unsigned int ival, unsigned int radix) {
char buf[32];
itoa(ival, buf, radix);
return String(buf);
}
/**
* Parse a string to generate an integer value
*
* @param str const String&
* @param radix unsigned int
* @return unsigned int
*/
unsigned int Integer::parseInt( const String& str, unsigned int radix) {
wchar_t* pEndPtr = NULL;
return (unsigned int) wcstoul( str.data(), &pEndPtr, radix);
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "util\Long.h"
using namespace Alfresco;
/**
* Convert a long/64 bit integer value to a hexadecimal string
*
* @param lval const LONG64
* @return String
*/
String Long::toHexString( const LONG64 lval) {
char buf[32];
sprintf( buf, "%I64x", lval);
return String(buf);
}
/**
* Convert a long/64 bit integer value to a decimal string
*
* @param lval const LONG64
* @return String
*/
String Long::toString( const LONG64 lval) {
char buf[32];
sprintf( buf, "%I64d", lval);
return String(buf);
}
/**
* Make a long/64bit value from the low/high 32bit values
*
* @param lowPart unsigned int
* @param highPart unsigned int
* @return LONG64
*/
LONG64 Long::makeLong( unsigned int lowPart, unsigned int highPart) {
LONG64 lVal = (LONG64) lowPart + (((LONG64) highPart) << 32);
return lVal;
}
/**
* Make a long/64bit value from the low/high 32bit values of the FILETIME structure
*
* @param fTime FILETIME
* @return LONG64
*/
LONG64 Long::makeLong( FILETIME fTime) {
LONG64 lVal = (LONG64) fTime.dwLowDateTime + (((LONG64) fTime.dwHighDateTime) << 32);
return lVal;
}
/**
* Parse a string to generate a long/64 bit integer value
*
* @param str const String&
* @param radix unsigned int
* @return LONG64
*/
LONG64 Long::parseLong( const String& str, unsigned int radix) {
wchar_t* pEndPtr = NULL;
return _wcstoui64( str.data(), &pEndPtr, radix);
}
/**
* Copy a long/64bit value to a FILETIME structure
*
* @param lval LONG64
* @param ftime FILETIME&
*/
void Long::copyTo( LONG64 lval, FILETIME& ftime) {
memcpy( &ftime, &lval, sizeof( LONG64));
}

View File

@@ -0,0 +1,889 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "util\String.h"
using namespace Alfresco;
using namespace std;
/**
* Default constructor
*/
String::String() {
m_string = std::wstring();
}
/**
* Class constructor
*
* @param alloc const unsigned int
*/
String::String(const unsigned int alloc) {
m_string = std::wstring();
m_string.reserve( alloc);
}
/**
* Class constructor
*
* @param str const char*
*/
String::String(const char* str) {
// Expand the characters to wide characters and append to the string
wchar_t wch;
while ( *str != '\0') {
wch = (wchar_t) *str++;
m_string += wch;
}
}
/**
* Class constructor
*
* @param str const unsigned char*
*/
String::String(const unsigned char* str) {
// Expand the characters to wide characters and append to the string
wchar_t wch;
while ( *str != '\0') {
wch = (wchar_t) *str++;
m_string += wch;
}
}
/**
* Class constructor
*
* @param buf const char*
* @param offset const unsigned int
* @param len const unsigned int
*/
String::String(const char* buf, const unsigned int offset, const unsigned int len) {
// Expand the characters to wide characters and append to the string
wchar_t wch;
const char* str = buf + offset;
unsigned int sLen = len;
while ( sLen--) {
wch = (wchar_t) *str++;
m_string += wch;
}
}
/**
* Class constructor
*
* @param str const wchar_t*
*/
String::String(const wchar_t* str) {
m_string = std::wstring( str);
}
/**
* Class constructor
*
* @param buf const wchar_t*
* @param offset const unsigned int
* @param len const unsigned int
*/
String::String(const wchar_t* buf, const unsigned int offset, const unsigned int len) {
m_string = std::wstring(buf + offset, len);
}
/**
* Class constructor
*
* @param str const std::wstring&
*/
String::String(const std::wstring& str) {
m_string = str;
}
/**
* Copy constructor
*
* @param str const String&
*/
String::String(const String& str) {
m_string = std::wstring(str.data());
}
/**
* Class constructor
*
* @param byts ByteArray&
*/
String::String( ByteArray& byts) {
// Expand the characters to wide characters and append to the string
wchar_t wch;
for ( unsigned int idx = 0; idx < byts.getLength(); idx++) {
wch = (wchar_t) byts[idx];
m_string += wch;
}
}
/**
* Compare strings for equality
*
* @param str const wchar_t*
* @return bool
*/
bool String::equals(const wchar_t* str) const {
// Check that the string is valid
if ( str == NULL)
return false;
// Compare the strings
if ( m_string.compare(str) == 0)
return true;
return false;
}
/**
* Compare strings for equality
*
* @param str const String&
* @return bool
*/
bool String::equals(const String& str) const {
// Compare the strings
if ( m_string.compare(str.data()) == 0)
return true;
return false;
}
/**
* Compare strings for equality ignoring case
*
* @param str const wchar_t*
* @return bool
*/
bool String::equalsIgnoreCase(const wchar_t* str) const {
return _wcsicmp( str, data()) == 0 ? true : false;
}
/**
* Compare strings for equality ignoring case
*
* @param str const String&
* @return bool
*/
bool String::equalsIgnoreCase(const String& str) const {
return _wcsicmp( str.data(), data()) == 0 ? true : false;
}
/**
* Compare strings
*
* @param str const String&
* @return int
*/
int String::compareTo( const String& str) const {
return m_string.compare( str.getString());
}
/**
* Compare strings
*
* @param pStr const wchar_t*
* @return int
*/
int String::compareTo( const wchar_t* pStr) const {
return m_string.compare( pStr);
}
/**
* Convert the string to lower case returning the resulting String
*
* @return String
*/
String String::toLowerCase() const {
// Create a copy of the string then convert to lowercase
std::wstring lstr(m_string);
for ( unsigned int i = 0; i < lstr.length(); i++)
lstr[i] = tolower(lstr[i]);
return String(lstr);
}
/**
* Convert the string to upper case returning the resulting String
*
* @return String
*/
String String::toUpperCase() const {
// Create a copy of the string then convert to uppercase
std::wstring ustr(m_string);
for ( unsigned int i = 0; i < ustr.length(); i++)
ustr[i] = toupper(ustr[i]);
return String(ustr);
}
/**
* Return the index of the specified character, or -1 if not found
*
* @param ch const wchar_t
* @param startIndex int
* @return int
*/
int String::indexOf(const wchar_t ch, int startIndex) const {
return (int) m_string.find_first_of( ch, startIndex);
}
/**
* Return the index of the specified string, or -1 if not found
*
* @param str const wchar_t*
* @param startIndex int
* @return int
*/
int String::indexOf(const wchar_t* str, int startIndex) const {
return (int) m_string.find_first_of( str, startIndex);
}
/**
* Return the index of the specified string, or -1 if not found
*
* @param str const String&
* @param startIndex int
* @return int
*/
int String::indexOf(const String& str, int startIndex) const {
return (int) m_string.find_first_of( str, startIndex);
}
/**
* Return the last index of the specified character, or -1 if not found
*
* @param ch const wchar_t
* @param startIndex int
* @return int
*/
int String::lastIndexOf(const wchar_t ch, int startIndex) const {
return (int) m_string.find_last_of( ch, startIndex);
}
/**
* Return the last index of the specified string, or -1 if not found
*
* @param str const wchar_t*
* @param startIndex int
* @return int
*/
int String::lastIndexOf(const wchar_t* str, int startIndex) const {
return (int) m_string.find_last_of( str, startIndex);
}
/**
* Return the last index of the specified string, or -1 if not found
*
* @param str const String&
* @param startIndex int
* @return int
*/
int String::lastIndexOf(const String& str, int startIndex) const {
return (int) m_string.find_last_of( str, startIndex);
}
/**
* Check if this string starts with the specified string.
*
* @param str const wchar_t*
* @return bool
*/
bool String::startsWith(const wchar_t* str) const {
// Check if the string to check is valid
if ( str == NULL)
return false;
// Get the string length, if the comparison string is longer than this string
// then there is no match.
size_t len = wcslen(str);
if ( str == NULL || wcslen(str) > m_string.length())
return false;
// Check if this string starts with the specified string
if ( m_string.compare(0, len, str) == 0)
return true;
return false;
}
/**
* Check if this string starts with the specified string.
*
* @param str const String&
* @return bool
*/
bool String::startsWith(const String& str) const {
// Get the string length, if the comparison string is longer than this string
// then there is no match.
if ( str.length() > m_string.length())
return false;
// Check if this string starts with the specified string
if ( m_string.compare(0, str.length(), str.data()) == 0)
return true;
return false;
}
/**
* Check if this string starts with the specified string, ignoring case.
*
* @param str const wchar_t*
* @return bool
*/
bool String::startsWithIgnoreCase(const wchar_t* str) const {
// Check if the string to check is valid
if ( str == NULL)
return false;
// Get the string length, if the comparison string is longer than this string
// then there is no match.
size_t len = wcslen(str);
if ( str == NULL || wcslen(str) > m_string.length())
return false;
// Check if this string starts with the specified string
if ( _wcsnicmp(str, data(), len) == 0)
return true;
return false;
}
/**
* Check if this string starts with the specified string, ignoring case.
*
* @param str const String&
* @return bool
*/
bool String::startsWithIgnoreCase(const String& str) const {
// Get the string length, if the comparison string is longer than this string
// then there is no match.
if ( str.length() > m_string.length())
return false;
// Check if this string starts with the specified string
if ( _wcsnicmp( str.data(), data(), str.length()) == 0)
return true;
return false;
}
/**
* Check if this string ends with the specified string.
*
* @param str const wchar_t*
* @return bool
*/
bool String::endsWith(const wchar_t* str) const {
// Check if the string to check is valid
if ( str == NULL)
return false;
// Get the string length, if the comparison string is longer than this string
// then there is no match.
size_t len = wcslen(str);
if ( str == NULL || wcslen(str) > m_string.length())
return false;
// Check if this string ends with the specified string
if ( m_string.compare(m_string.length() - len, len, str) == 0)
return true;
return false;
}
/**
* Check if this string ends with the specified string.
*
* @param str const String&
* @return bool
*/
bool String::endsWith(const String& str) const {
// Get the string length, if the comparison string is longer than this string
// then there is no match.
if ( str.length() > m_string.length())
return false;
// Check if this string ends with the specified string
if ( m_string.compare(m_string.length() - str.length(), str.length(), str.data()) == 0)
return true;
return false;
}
/**
* Trim leading and trailing whitespace from the string returning the resulting String
*
* @return String
*/
String String::trim( void) const {
std::wstring str = m_string;
str.erase( str.find_last_not_of( L" ") + 1);
return String( str);
}
/**
* Return a substring of this string
*
* @param beginIndex unsigned int
* @return String
*/
String String::substring( unsigned int beginIndex) const {
std::wstring str = m_string.substr( beginIndex);
return String(str);
}
/**
* Return a substring of this string
*
* @param beginIndex unsigned int
* @param endIndex unsigned int
* @return String
*/
String String::substring( unsigned int beginIndex, unsigned int endIndex) const {
std::wstring str = m_string.substr( beginIndex, (endIndex - beginIndex));
return String(str);
}
/**
* Assignment operator
*
* @param str const wchar_t*
* @return String&
*/
String& String::operator=(const wchar_t* str) {
m_string = str;
return *this;
}
/**
* Assignment operator
*
* @param str const String&
* @return String&
*/
String& String::operator=(const String& str) {
m_string = str.data();
return *this;
}
/**
* Return the string as an array of 8 bit bytes.
*
* @param byts ByteArray&
* @return ByteArray
*/
ByteArray String::getBytes( ByteArray& byts) const {
// Create a byte array to hold the byte data
byts.setLength( length());
// Convert the wide characters to ASCII characters
for ( unsigned int i = 0; i < length(); i++)
byts[ i] = (char) (charAt(i) & 0xFF);
return byts;
}
/**
* Return the string as an array of 8 bit bytes.
*
* @return ByteArray
*/
ByteArray String::getBytes( void) const {
// Create a byte array to hold the byte data
ByteArray byts;
byts.setLength( length());
// Convert the wide characters to ASCII characters
for ( unsigned int i = 0; i < length(); i++)
byts[ i] = (char) (charAt(i) & 0xFF);
return byts;
}
/**
* Equality operator
*
* @param str const String&
* @return bool
*/
bool String::operator== ( const String& str) const {
return equals( str);
}
/**
* Equality operator
*
* @param str const wchar_t*
* @return bool
*/
bool String::operator== ( const wchar_t* str) const {
return equals( str);
}
/**
* Equality operator
*
* @param str const char*
* @return bool
*/
bool String::operator== ( const char* str) const {
return equals( String( str));
}
/**
* Wide character output stream operator
*
* @param out wostream&
* @param str const String&
* @return wostream&
*/
std::wostream& Alfresco::operator<< ( std::wostream& out, const Alfresco::String& str) {
return out << str.data();
}
/**
* Less than operator
*
* @param str const String&
* @return bool
*/
bool String::operator<( const String& str) const {
return getString().compare( str.getString()) < 0 ? true : false;
}
/**
* ASCII character output stream operator
*
* @param out ostream&
* @param str const String&
* @return ostream&
*/
std::ostream& Alfresco::operator<< ( std::ostream& out, const Alfresco::String& str) {
std::string ascStr;
ascStr.reserve( str.length());
for ( unsigned int i = 0; i < str.length(); i++)
ascStr += (char) ( str.charAt( i) & 0xFF);
return out << ascStr.c_str();
}
/**
* Replace occurrences of the character oldCh with newCh
*
* @param oldCh wchar_t
* @param newCh wchar_t
*/
void String::replace( wchar_t oldCh, wchar_t newCh) {
if ( m_string.size() == 0)
return;
for ( unsigned int i = 0; i < m_string.size(); i++) {
if ( m_string.at( i) == oldCh)
m_string[i] = newCh;
}
}
/**
* Append a character to this string
*
* @param ch wchar_t
*/
void String::append( wchar_t ch) {
m_string += ch;
}
/**
* Append a string to this string
*
* @param str const char*
*/
void String::append ( const char* str) {
// Expand the characters to wide characters and append to the string
wchar_t wch;
while ( *str != '\0') {
wch = (wchar_t) *str++;
m_string += wch;
}
}
/**
* Append a string to this string
*
* @param str const wchar_t*
*/
void String::append (const wchar_t* str) {
m_string += str;
}
/**
* Append a string to this string
*
* @param str const String&
*/
void String::append (const String& str) {
m_string += str.getString();
}
/**
* Append an integer value to this string
*
* @param ival const unsigned int
*/
void String::append (const unsigned int ival) {
wchar_t buf[32];
swprintf( buf, L"%u", ival);
m_string += buf;
}
/**
* Append a long value to this string
*
* @param lval const unsigned long
*/
void String::append (const unsigned long lval) {
wchar_t buf[32];
swprintf( buf, L"%lu", lval);
m_string += buf;
}
/**
* Append a long/64 bit value to this string
*
* @param l64val const unsigned long
*/
void String::append (const LONG64 l64val) {
wchar_t buf[32];
swprintf( buf, L"%I64u", l64val);
m_string += buf;
}
/**
* Split a string into tokens
*
* @param delims const String&
* @return StringList
*/
StringList String::tokenize( const String& delims) const {
// Skip leading delimiters
StringList tokens;
string::size_type lastPos = m_string.find_first_not_of( delims, 0);
// Find a non-delimiter character
string::size_type pos = m_string.find_first_of( delims, lastPos);
while ( pos != string::npos || lastPos != string::npos) {
// Add the current token to the list
tokens.addString( m_string.substr( lastPos, pos - lastPos));
// Skip delimiter(s)
lastPos = m_string.find_first_not_of( delims, pos);
// Find next token
pos = m_string.find_first_of( delims, lastPos);
}
// Return the token list
return tokens;
}
/**
* Default constructor
*/
StringList::StringList( void) {
}
/**
* Class constructor
*
* @param reserve unsigned int
*/
StringList::StringList( unsigned int reserve) {
m_list.reserve( reserve);
}
/**
* Copy constructor
*
* @param strList const StringList&
*/
StringList::StringList( const StringList& strList) {
copyFrom( strList);
}
/**
* Copy strings from the specified list
*
* @param strList const StringList&
*/
void StringList::copyFrom( const StringList& strList) {
for ( unsigned int idx = 0; idx < strList.numberOfStrings(); idx++)
addString( strList.getStringAt( idx));
}
/**
* Check if the list contains the string
*
* @param str const String&
* @return bool
*/
bool StringList::containsString ( const String& str) {
for ( std::vector<String>::iterator pos = m_list.begin(); pos < m_list.end(); pos++) {
if ( str.equals( *pos))
return true;
}
return false;
}
/**
* Check if the list contains the string, ignoring case
*
* @param str const String&
* @return bool
*/
bool StringList::containsStringCaseless ( const String& str) {
for ( std::vector<String>::iterator pos = m_list.begin(); pos < m_list.end(); pos++) {
if ( str.equalsIgnoreCase( *pos))
return true;
}
return false;
}
/**
* Find the specified string and return the position within the list, or -1 if not found
*
* @param str const String&
* @return int
*/
int StringList::indexOf( const String& str) const {
for ( unsigned int i = 0; i < m_list.size(); i++) {
if ( m_list[i].equals( str))
return (int) i;
}
return -1;
}
/**
* Remove the specified string from the list
*
* @param str const String&
*/
void StringList::removeString ( const String& str) {
for ( std::vector<String>::iterator pos = m_list.begin(); pos < m_list.end(); pos++) {
if ( str.equals( *pos)) {
m_list.erase( pos);
return;
}
}
}
/**
* Remove the specified string from the list, ignoring case
*
* @param str const String&
*/
void StringList::removeStringCaseless ( const String& str) {
for ( std::vector<String>::iterator pos = m_list.begin(); pos < m_list.end(); pos++) {
if ( str.equalsIgnoreCase( *pos)) {
m_list.erase( pos);
return;
}
}
}
/**
* Return the string list as a comma separated string
*
* @return String
*/
String StringList::toString( void) const {
String ret;
for ( unsigned int i = 0; i < numberOfStrings(); i++) {
ret += getStringAt( i);
ret += ",";
}
return ret;
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
#include "util\System.h"
#include <sys\timeb.h>
using namespace Alfresco;
/**
* Return the current system time in milliseconds since Jan 1 1970
*
* @return DATETIME
*/
DATETIME System::currentTimeMillis( void) {
// Get the current system time
struct __timeb64 timeNow;
_ftime64( &timeNow);
// Build the milliseconds time
DATETIME timeNowMillis = ( timeNow.time * 1000L) + (DATETIME) timeNow.millitm;
return timeNowMillis;
}

View File

@@ -0,0 +1,7 @@
// stdafx.cpp : source file that includes just the standard includes
// CAlfrescoApp.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"

View File

@@ -0,0 +1,44 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently,
// but are changed infrequently
#pragma once
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#endif
// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later.
#define WINVER 0x0400 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
#endif
#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later.
#define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
#endif
#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
#endif
#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later.
#define _WIN32_IE 0x0400 // Change this to the appropriate value to target IE 5.0 or later.
#endif
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
// turns off MFC's hiding of some common and often safely ignored warning messages
#define _AFX_ALL_WARNINGS
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdisp.h> // MFC Automation classes
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
#include <afxdhtml.h> // HTML Dialogs
#include <afxcview.h>

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.cache;
import java.io.Serializable;
import org.alfresco.error.AlfrescoRuntimeException;
import org.jboss.cache.Fqn;
import org.jboss.cache.TreeCache;
/**
* A thin adapter for <b>TreeCache</b> support.
*
* @author Derek Hulley
*/
public class TreeCacheAdapter<K extends Serializable, V extends Serializable>
implements SimpleCache<K, V>
{
private TreeCache cache;
private Fqn regionFqn;
public TreeCacheAdapter()
{
}
/**
* @param cache the backing Ehcache instance
*/
public void setCache(TreeCache cache)
{
this.cache = cache;
}
/**
* Set the uniquely named region of the cache within which all object must be cached
*
* @param regionName the cache region
*/
public void setRegionName(String regionName)
{
this.regionFqn = new Fqn(regionName);
}
public boolean contains(K key)
{
try
{
return cache.exists(regionFqn, key);
}
catch (Throwable e)
{
throw new AlfrescoRuntimeException("contains failed", e);
}
}
@SuppressWarnings("unchecked")
public V get(K key)
{
try
{
Object element = cache.get(regionFqn, key);
if (element != null)
{
return (V) element;
}
else
{
return null;
}
}
catch (Throwable e)
{
throw new AlfrescoRuntimeException("Failed to get from TreeCache: \n" +
" key: " + key,
e);
}
}
public void put(K key, V value)
{
try
{
cache.put(regionFqn, key, value);
}
catch (Throwable e)
{
throw new AlfrescoRuntimeException("Failed to put into TreeCache: \n" +
" key: " + key + "\n" +
" value: " + value,
e);
}
}
public void remove(K key)
{
try
{
cache.remove(regionFqn, key);
}
catch (Throwable e)
{
throw new AlfrescoRuntimeException("Failed to remove from TreeCache: \n" +
" key: " + key,
e);
}
}
public void clear()
{
try
{
cache.remove(regionFqn);
}
catch (Throwable e)
{
throw new AlfrescoRuntimeException("Failed to clear cache", e);
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.cache;
import java.io.Serializable;
import org.jboss.cache.DummyTransactionManagerLookup;
import org.jboss.cache.Fqn;
import org.jboss.cache.TreeCache;
import junit.framework.TestCase;
/**
* @see org.alfresco.repo.cache.TreeCacheAdapter
*
* @author Derek Hulley
*/
public class TreeCacheAdapterTest extends TestCase
{
private static final String KEY_A = "A";
private static final String VALUE_A = "AAA";
private static final String KEY_B = "B";
private static final String VALUE_B = "BBB";
private TreeCache treeCache;
private TreeCacheAdapter<Serializable, Serializable> cache;
@Override
public void setUp() throws Exception
{
treeCache = new TreeCache();
treeCache.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
treeCache.start();
cache = new TreeCacheAdapter<Serializable, Serializable>();
cache.setCache(treeCache);
cache.setRegionName(getName());
}
public void testSimplePutGet() throws Exception
{
cache.put(KEY_A, VALUE_A);
cache.put(KEY_B, VALUE_B);
// check that this is present in the underlying cache
Serializable checkValueA = (Serializable) treeCache.get(new Fqn(getName()), KEY_A);
assertNotNull("Value A is not present in underlying cache", checkValueA);
assertEquals("Value A is incorrect in underlying cache", VALUE_A, checkValueA);
Serializable checkValueB = cache.get(KEY_B);
assertNotNull("Value B is not present in cache", checkValueB);
assertEquals("Value B is incorrect in cache", VALUE_B, checkValueB);
}
}

View File

@@ -0,0 +1,277 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.content.replication;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.node.index.IndexRecovery;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* This component performs one-way replication between to content stores.
* <p>
* It ensure that the content from the first store is copied to the second
* store where required, therefore primarily acting as a backup or
* replication mechanism.
* <p>
* Once started, this process runs continuously on a low-priority thread
* and cannot be restarted.
*
* @author Derek Hulley
*/
public class ContentStoreReplicator
{
private static Log logger = LogFactory.getLog(ContentStoreReplicator.class);
private ContentStore sourceStore;
private ContentStore targetStore;
/** used to ensure that this instance gets started once only */
private boolean started;
/** set this on to keep replicating and never stop. The default is <code>true</code>. */
private boolean runContinuously;
/** the time to wait between passes */
private long waitTime;
public ContentStoreReplicator()
{
this.started = false;
this.runContinuously = true;
this.waitTime = 60000L;
}
/**
* Set the source that content must be taken from
*
* @param sourceStore the content source
*/
public void setSourceStore(ContentStore sourceStore)
{
this.sourceStore = sourceStore;
}
/**
* Set the target that content must be written to
*
* @param targetStore the content target
*/
public void setTargetStore(ContentStore targetStore)
{
this.targetStore = targetStore;
}
/**
* Set whether the thread should run continuously or terminate after
* a first pass.
*
* @param runContinuously true to run continously (default)
*/
public void setRunContinuously(boolean runContinuously)
{
this.runContinuously = runContinuously;
}
/**
* Set the time to wait between replication passes (in seconds)
*
* @param waitTime the time between passes (in seconds). Default is 60s.
*/
public void setWaitTime(long waitTime)
{
// convert to millis
this.waitTime = waitTime * 1000L;
}
/**
* Kick off the replication thread. This method can be used once.
*/
public synchronized void start()
{
if (started)
{
throw new AlfrescoRuntimeException("This ContentStoreReplicator has already been started");
}
// create a low-priority, daemon thread to do the work
Runnable runnable = new ReplicationRunner();
Thread thread = new Thread(runnable);
thread.setPriority(Thread.MIN_PRIORITY);
thread.setDaemon(true);
// start it
thread.start();
}
/**
* Stateful thread runnable that performs the replication.
*
* @author Derek Hulley
*/
private class ReplicationRunner implements Runnable
{
public void run()
{
// keep this thread going permanently
while (true)
{
try
{
ContentStoreReplicator.this.replicate();
// check if the process should terminate
if (!runContinuously)
{
// the thread has caught up with all the available work and should not
// run continuously
if (logger.isDebugEnabled())
{
logger.debug("Thread quitting - first pass of replication complete:");
}
break;
}
// pause the the required wait time
synchronized(ContentStoreReplicator.this)
{
ContentStoreReplicator.this.wait(waitTime);
}
}
catch (InterruptedException e)
{
// ignore
}
catch (Throwable e)
{
// report
logger.error("Replication failure", e);
}
}
}
}
/**
* Perform a full replication of all source to target URLs.
*/
private void replicate()
{
// get all the URLs from the source
Set<String> sourceUrls = sourceStore.getUrls();
// get all the URLs from the target
Set<String> targetUrls = targetStore.getUrls();
// remove source URLs that are present in the target
sourceUrls.removeAll(targetUrls);
// ensure that each remaining source URL is present in the target
for (String contentUrl : sourceUrls)
{
replicate(contentUrl);
}
}
/**
* Checks if the target store has the URL, and if not, replicates the content.
* <p>
* Any failures are reported and not thrown, but the target URL is removed for
* good measure.
*
* @param contentUrl the URL to replicate
*/
private void replicate(String contentUrl)
{
try
{
// check that the target doesn't have it
if (targetStore.exists(contentUrl))
{
// ignore this as the target has it already
if (logger.isDebugEnabled())
{
logger.debug("No replication required - URL exists in target store: \n" +
" source store: " + sourceStore + "\n" +
" target store: " + targetStore + "\n" +
" content URL: " + contentUrl);
}
return;
}
// get a writer to the target store - this can fail if the content is there now
ContentWriter writer = targetStore.getWriter(null, contentUrl);
// get the source reader
ContentReader reader = sourceStore.getReader(contentUrl);
if (!reader.exists())
{
// the content may have disappeared from the source store
if (logger.isDebugEnabled())
{
logger.debug("Source store no longer has URL - no replication possible: \n" +
" source store: " + sourceStore + "\n" +
" target store: " + targetStore + "\n" +
" content URL: " + contentUrl);
}
return;
}
// copy from the reader to the writer
writer.putContent(reader);
}
catch (Throwable e)
{
logger.error("Failed to replicate URL - removing target content: \n" +
" source store: " + sourceStore + "\n" +
" target store: " + targetStore + "\n" +
" content URL: " + contentUrl,
e);
targetStore.delete(contentUrl);
}
}
/**
* Kicks off the {@link ContentStoreReplicator content store replicator}.
*
* @author Derek Hulley
*/
public class ContentStoreReplicatorJob implements Job
{
/** KEY_CONTENT_STORE_REPLICATOR = 'contentStoreReplicator' */
public static final String KEY_CONTENT_STORE_REPLICATOR = "contentStoreReplicator";
/**
* Forces a full index recovery using the {@link IndexRecovery recovery component} passed
* in via the job detail.
*/
public void execute(JobExecutionContext context) throws JobExecutionException
{
ContentStoreReplicator contentStoreReplicator = (ContentStoreReplicator) context.getJobDetail()
.getJobDataMap().get(KEY_CONTENT_STORE_REPLICATOR);
if (contentStoreReplicator == null)
{
throw new JobExecutionException("Missing job data: " + KEY_CONTENT_STORE_REPLICATOR);
}
// reindex
contentStoreReplicator.start();
}
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.content.replication;
import java.io.File;
import java.util.Set;
import junit.framework.TestCase;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.filestore.FileContentStore;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.util.GUID;
import org.alfresco.util.TempFileProvider;
/**
* Tests the content store replicator.
*
* @see org.alfresco.repo.content.replication.ContentStoreReplicator
*
* @author Derek Hulley
*/
@SuppressWarnings("unused")
public class ContentStoreReplicatorTest extends TestCase
{
private static final String SOME_CONTENT = "The No. 1 Ladies' Detective Agency";
private ContentStoreReplicator replicator;
private ContentStore sourceStore;
private ContentStore targetStore;
@Override
public void setUp() throws Exception
{
super.setUp();
File tempDir = TempFileProvider.getTempDir();
// create the source file store
String storeDir = tempDir.getAbsolutePath() + File.separatorChar + getName() + File.separatorChar + GUID.generate();
sourceStore = new FileContentStore(storeDir);
// create the target file store
storeDir = tempDir.getAbsolutePath() + File.separatorChar + getName() + File.separatorChar + GUID.generate();
targetStore = new FileContentStore(storeDir);
// create the replicator
replicator = new ContentStoreReplicator();
replicator.setSourceStore(sourceStore);
replicator.setTargetStore(targetStore);
replicator.setRunContinuously(false); // replicate once
replicator.setWaitTime(0);
}
/**
* Creates a source with some files and replicates in a single pass, checking the results.
*/
public void testSinglePassReplication() throws Exception
{
ContentWriter writer = sourceStore.getWriter(null, null);
writer.putContent("123");
// replicate
replicator.start();
// wait a second
synchronized(this)
{
this.wait(1000L);
}
assertTrue("Target store doesn't have content added to source",
targetStore.exists(writer.getContentUrl()));
// this was a single pass, so now more replication should be done
writer = sourceStore.getWriter(null, null);
writer.putContent("456");
// wait a second
synchronized(this)
{
this.wait(1000L);
}
assertFalse("Replication should have been single-pass",
targetStore.exists(writer.getContentUrl()));
}
/**
* Adds content to the source while the replicator is going as fast as possible.
* Just to make it more interesting, the content is sometimes put in the target
* store as well.
* <p>
* Afterwards, some content is removed from the the target.
* <p>
* Then, finally, a check is performed to ensure that the source and target are
* in synch.
*/
public void testContinuousReplication() throws Exception
{
replicator.setRunContinuously(true);
replicator.setWaitTime(0L);
replicator.start();
String duplicateUrl = AbstractContentStore.createNewUrl();
// start the replicator - it won't wait between iterations
for (int i = 0; i < 10; i++)
{
// put some content into both the target and source
duplicateUrl = AbstractContentStore.createNewUrl();
ContentWriter duplicateTargetWriter = targetStore.getWriter(null, duplicateUrl);
ContentWriter duplicateSourceWriter = sourceStore.getWriter(null, duplicateUrl);
duplicateTargetWriter.putContent("Duplicate Target Content: " + i);
duplicateSourceWriter.putContent(duplicateTargetWriter.getReader());
for (int j = 0; j < 100; j++)
{
// write content
ContentWriter writer = sourceStore.getWriter(null, null);
writer.putContent("Repeated put: " + j);
}
}
// remove the last duplicated URL from the target
targetStore.delete(duplicateUrl);
// allow time for the replicator to catch up
synchronized(this)
{
this.wait(1000L);
}
// check that we have an exact match of URLs
Set<String> sourceUrls = sourceStore.getUrls();
Set<String> targetUrls = targetStore.getUrls();
sourceUrls.containsAll(targetUrls);
targetUrls.contains(sourceUrls);
}
}

View File

@@ -0,0 +1,447 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.content.replication;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentStreamListener;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* </h1><u>Replicating Content Store</u></h1>
* <p>
* A content store implementation that is able to replicate content between stores.
* Content is not persisted by this store, but rather it relies on any number of
* child {@link org.alfresco.repo.content.ContentStore stores} to provide access to
* content readers and writers.
* <p>
* The order in which the stores appear in the list of stores participating is
* important. The first store in the list is known as the <i>primary store</i>.
* When the replicator goes to fetch content, the stores are searched
* from first to last. The stores should therefore be arranged in order of
* speed.
* <p>
* It supports the notion of inbound and/or outbound replication, both of which can be
* operational at the same time.
*
* </h2><u>Outbound Replication</u></h2>
* <p>
* When this is enabled, then the primary store is used for writes. When the
* content write completes (i.e. the write channel is closed) then the content
* is synchronously copied to all other stores. The write is therefore slowed
* down, but the content replication will occur <i>in-transaction</i>.
* <p>
* The {@link #setOutboundThreadPoolExecutor(boolean) outboundThreadPoolExecutor }
* property to enable asynchronous replication.<br>
* With asynchronous replication, there is always a risk that a failure
* occurs during the replication. Depending on the configuration of the server,
* further action may need to be taken to rectify the problem manually.
*
* </h2><u>Inbound Replication</u></h2>
* <p>
* This can be used to lazily replicate content onto the primary store. When
* content can't be found in the primary store, the other stores are checked
* in order. If content is found, then it is copied into the local store
* before being returned. Subsequent accesses will use the primary store.<br>
* This should be used where the secondary stores are much slower, such as in
* the case of a store against some kind of archival mechanism.
*
* <h2><u>No Replication</u></h2>
* <p>
* Content is not written to the primary store only. The other stores are
* only used to retrieve content and the primary store is not updated with
* the content.
*
* @author Derek Hulley
*/
public class ReplicatingContentStore extends AbstractContentStore
{
/*
* The replication process uses thread synchronization as it can
* decide to write content to specific URLs during requests for
* a reader.
* While this won't help the underlying stores if there are
* multiple replications on top of them, it will prevent repeated
* work from multiple threads entering an instance of this component
* looking for the same content at the same time.
*/
private static Log logger = LogFactory.getLog(ReplicatingContentStore.class);
private TransactionService transactionService;
private ContentStore primaryStore;
private List<ContentStore> secondaryStores;
private boolean inbound;
private boolean outbound;
private ThreadPoolExecutor outboundThreadPoolExecutor;
private Lock readLock;
private Lock writeLock;
/**
* Default constructor set <code>inbound = false</code> and <code>outbound = true</code>;
*/
public ReplicatingContentStore()
{
inbound = false;
outbound = true;
ReadWriteLock storeLock = new ReentrantReadWriteLock();
readLock = storeLock.readLock();
writeLock = storeLock.writeLock();
}
/**
* Required to ensure that content listeners are executed in a transaction
*
* @param transactionService
*/
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
/**
* Set the primary store that content will be replicated to or from
*
* @param primaryStore the primary content store
*/
public void setPrimaryStore(ContentStore primaryStore)
{
this.primaryStore = primaryStore;
}
/**
* Set the secondary stores that this component will replicate to or from
*
* @param stores a list of stores to replicate to or from
*/
public void setSecondaryStores(List<ContentStore> secondaryStores)
{
this.secondaryStores = secondaryStores;
}
/**
* Set whether or not this component should replicate content to the
* primary store if not found.
*
* @param inbound true to pull content onto the primary store when found
* on one of the other stores
*/
public void setInbound(boolean inbound)
{
this.inbound = inbound;
}
/**
* Set whether or not this component should replicate content to all stores
* as it is written.
*
* @param outbound true to enable synchronous replication to all stores
*/
public void setOutbound(boolean outbound)
{
this.outbound = outbound;
}
/**
* Set the thread pool executer
*
* @param outboundThreadPoolExecutor set this to have the synchronization occur in a separate
* thread
*/
public void setOutboundThreadPoolExecutor(ThreadPoolExecutor outboundThreadPoolExecutor)
{
this.outboundThreadPoolExecutor = outboundThreadPoolExecutor;
}
/**
* Forwards the call directly to the first store in the list of stores.
*/
public ContentReader getReader(String contentUrl) throws ContentIOException
{
if (primaryStore == null)
{
throw new AlfrescoRuntimeException("ReplicatingContentStore not initialised");
}
// get a read lock so that we are sure that no replication is underway
ContentReader existingContentReader = null;
readLock.lock();
try
{
// get a reader from the primary store
ContentReader primaryReader = primaryStore.getReader(contentUrl);
// give it straight back if the content is there
if (primaryReader.exists())
{
return primaryReader;
}
// the content is not in the primary reader so we have to go looking for it
ContentReader secondaryContentReader = null;
for (ContentStore store : secondaryStores)
{
ContentReader reader = store.getReader(contentUrl);
if (reader.exists())
{
// found the content in a secondary store
secondaryContentReader = reader;
break;
}
}
// we already know that the primary has nothing
// drop out if no content was found
if (secondaryContentReader == null)
{
return primaryReader;
}
// secondary content was found
// return it if we are not doing inbound
if (!inbound)
{
return secondaryContentReader;
}
// we have to replicate inbound
existingContentReader = secondaryContentReader;
}
finally
{
readLock.unlock();
}
// -- a small gap for concurrent threads to get through --
// do inbound replication
writeLock.lock();
try
{
// double check the primary
ContentReader primaryContentReader = primaryStore.getReader(contentUrl);
if (primaryContentReader.exists())
{
// we were beaten to it
return primaryContentReader;
}
// get a writer
ContentWriter primaryContentWriter = primaryStore.getWriter(existingContentReader, contentUrl);
// copy it over
primaryContentWriter.putContent(existingContentReader);
// get a writer to the new content
primaryContentReader = primaryContentWriter.getReader();
// done
return primaryContentReader;
}
finally
{
writeLock.unlock();
}
}
/**
*
*/
public ContentWriter getWriter(ContentReader existingContentReader, String newContentUrl) throws ContentIOException
{
// get the writer
ContentWriter writer = primaryStore.getWriter(existingContentReader, newContentUrl);
// attach a replicating listener if outbound replication is on
if (outbound)
{
if (logger.isDebugEnabled())
{
logger.debug(
"Attaching " + (outboundThreadPoolExecutor == null ? "" : "a") + "synchronous " +
"replicating listener to local writer: \n" +
" primary store: " + primaryStore + "\n" +
" writer: " + writer);
}
// attach the listener
ContentStreamListener listener = new ReplicatingWriteListener(secondaryStores, writer, outboundThreadPoolExecutor);
writer.addListener(listener);
writer.setTransactionService(transactionService); // mandatory when listeners are added
}
// done
return writer;
}
/**
* Performs a delete on the local store and if outbound replication is on, propogates
* the delete to the other stores too.
*
* @return Returns the value returned by the delete on the primary store.
*/
public boolean delete(String contentUrl) throws ContentIOException
{
// delete on the primary store
boolean deleted = primaryStore.delete(contentUrl);
// propogate outbound deletions
if (outbound)
{
for (ContentStore store : secondaryStores)
{
store.delete(contentUrl);
}
// log
if (logger.isDebugEnabled())
{
logger.debug("Propagated content delete to " + secondaryStores.size() + " stores:" + contentUrl);
}
}
// done
if (logger.isDebugEnabled())
{
logger.debug("Deleted content for URL: " + contentUrl);
}
return deleted;
}
/**
* @return Returns the results as given by the primary store, and if inbound
* replication is active, merges the URLs from the secondary stores.
*/
public Set<String> getUrls(Date createdAfter, Date createdBefore) throws ContentIOException
{
Set<String> urls = new HashSet<String>(1024);
// add in URLs from primary store
Set<String> primaryUrls = primaryStore.getUrls(createdAfter, createdBefore);
urls.addAll(primaryUrls);
// add in URLs from secondary stores (they are visible for reads)
for (ContentStore secondaryStore : secondaryStores)
{
Set<String> secondaryUrls = secondaryStore.getUrls(createdAfter, createdBefore);
// merge them
urls.addAll(secondaryUrls);
}
// done
if (logger.isDebugEnabled())
{
logger.debug("Found " + urls.size() + " URLs, of which " + primaryUrls.size() + " are primary: \n" +
" created after: " + createdAfter + "\n" +
" created before: " + createdBefore);
}
return urls;
}
/**
* Replicates the content upon stream closure. If the thread pool is available,
* then the process will be asynchronous.
* <p>
* No transaction boundaries have been declared as the
* {@link ContentWriter#addListener(ContentStreamListener)} method indicates that
* all listeners will be called within a transaction.
*
* @author Derek Hulley
*/
public static class ReplicatingWriteListener implements ContentStreamListener
{
private List<ContentStore> stores;
private ContentWriter writer;
private ThreadPoolExecutor threadPoolExecutor;
public ReplicatingWriteListener(
List<ContentStore> stores,
ContentWriter writer,
ThreadPoolExecutor threadPoolExecutor)
{
this.stores = stores;
this.writer = writer;
this.threadPoolExecutor = threadPoolExecutor;
}
public void contentStreamClosed() throws ContentIOException
{
Runnable runnable = new ReplicateOnCloseRunnable();
if (threadPoolExecutor == null)
{
// execute direct
runnable.run();
}
else
{
threadPoolExecutor.execute(runnable);
}
}
/**
* Performs the actual replication work.
*
* @author Derek Hulley
*/
private class ReplicateOnCloseRunnable implements Runnable
{
public void run()
{
for (ContentStore store : stores)
{
try
{
// replicate the content to the store - we know the URL that we want to write to
ContentReader reader = writer.getReader();
String contentUrl = reader.getContentUrl();
// in order to replicate, we have to specify the URL that we are going to write to
ContentWriter replicatedWriter = store.getWriter(null, contentUrl);
// write it
replicatedWriter.putContent(reader);
if (logger.isDebugEnabled())
{
logger.debug("Replicated content to store: \n" +
" url: " + contentUrl + "\n" +
" to store: " + store);
}
}
catch (Throwable e)
{
throw new ContentIOException("Content replication failed: \n" +
" url: " + writer.getContentUrl() + "\n" +
" to store: " + store);
}
}
}
}
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.content.replication;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.alfresco.repo.content.AbstractContentReadWriteTest;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.filestore.FileContentStore;
import org.alfresco.repo.transaction.DummyTransactionService;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.util.GUID;
import org.alfresco.util.TempFileProvider;
/**
* Tests read and write functionality for the replicating store.
* <p>
* By default, replication is off for both the inbound and outbound
* replication. Specific tests change this.
*
* @see org.alfresco.repo.content.replication.ReplicatingContentStore
*
* @author Derek Hulley
*/
public class ReplicatingContentStoreTest extends AbstractContentReadWriteTest
{
private static final String SOME_CONTENT = "The No. 1 Ladies' Detective Agency";
private ReplicatingContentStore replicatingStore;
private ContentStore primaryStore;
private List<ContentStore> secondaryStores;
@Override
public void setUp() throws Exception
{
super.setUp();
File tempDir = TempFileProvider.getTempDir();
// create a primary file store
String storeDir = tempDir.getAbsolutePath() + File.separatorChar + GUID.generate();
primaryStore = new FileContentStore(storeDir);
// create some secondary file stores
secondaryStores = new ArrayList<ContentStore>(3);
for (int i = 0; i < 3; i++)
{
storeDir = tempDir.getAbsolutePath() + File.separatorChar + GUID.generate();
ContentStore store = new FileContentStore(storeDir);
secondaryStores.add(store);
}
replicatingStore = new ReplicatingContentStore();
replicatingStore.setTransactionService(new DummyTransactionService());
replicatingStore.setPrimaryStore(primaryStore);
replicatingStore.setSecondaryStores(secondaryStores);
replicatingStore.setOutbound(false);
replicatingStore.setInbound(false);
}
@Override
public ContentStore getStore()
{
return replicatingStore;
}
/**
* Performs checks necessary to ensure the proper replication of content for the given
* URL
*/
private void checkForReplication(boolean inbound, boolean outbound, String contentUrl, String content)
{
if (inbound)
{
ContentReader reader = primaryStore.getReader(contentUrl);
assertTrue("Content was not replicated into the primary store", reader.exists());
assertEquals("The replicated content was incorrect", content, reader.getContentString());
}
if (outbound)
{
for (ContentStore store : secondaryStores)
{
ContentReader reader = store.getReader(contentUrl);
assertTrue("Content was not replicated out to the secondary stores within a second", reader.exists());
assertEquals("The replicated content was incorrect", content, reader.getContentString());
}
}
}
/**
* Checks that the url is present in each of the stores
*
* @param contentUrl
* @param mustExist true if the content must exist, false if it must <b>not</b> exist
*/
private void checkForUrl(String contentUrl, boolean mustExist)
{
// check that the URL is present for each of the stores
for (ContentStore store : secondaryStores)
{
Set<String> urls = store.getUrls();
assertTrue("URL of new content not present in store", urls.contains(contentUrl) == mustExist);
}
}
public void testNoReplication() throws Exception
{
ContentWriter writer = getWriter();
writer.putContent(SOME_CONTENT);
checkForReplication(false, false, writer.getContentUrl(), SOME_CONTENT);
}
public void testOutboundReplication() throws Exception
{
replicatingStore.setOutbound(true);
// write some content
ContentWriter writer = getWriter();
writer.putContent(SOME_CONTENT);
String contentUrl = writer.getContentUrl();
checkForReplication(false, true, contentUrl, SOME_CONTENT);
// check for outbound deletes
replicatingStore.delete(contentUrl);
checkForUrl(contentUrl, false);
}
public void testAsyncOutboundReplication() throws Exception
{
ThreadPoolExecutor tpe = new ThreadPoolExecutor(1, 1, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
replicatingStore.setOutbound(true);
replicatingStore.setOutboundThreadPoolExecutor(tpe);
// write some content
ContentWriter writer = getWriter();
writer.putContent(SOME_CONTENT);
String contentUrl = writer.getContentUrl();
// wait for a second
synchronized(this)
{
this.wait(1000L);
}
checkForReplication(false, true, contentUrl, SOME_CONTENT);
// check for outbound deletes
replicatingStore.delete(contentUrl);
checkForUrl(contentUrl, false);
}
public void testInboundReplication() throws Exception
{
replicatingStore.setInbound(false);
// pick a secondary store and write some content to it
ContentStore secondaryStore = secondaryStores.get(2);
ContentWriter writer = secondaryStore.getWriter(null, null);
writer.putContent(SOME_CONTENT);
String contentUrl = writer.getContentUrl();
// get a reader from the replicating store
ContentReader reader = replicatingStore.getReader(contentUrl);
assertTrue("Reader must have been found in secondary store", reader.exists());
// set inbound replication on and repeat
replicatingStore.setInbound(true);
reader = replicatingStore.getReader(contentUrl);
// this time, it must have been replicated to the primary store
checkForReplication(true, false, contentUrl, SOME_CONTENT);
}
}

View File

@@ -0,0 +1,769 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.node.index;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.NodeStatus;
import org.alfresco.repo.search.Indexer;
import org.alfresco.repo.search.impl.lucene.LuceneIndexerImpl;
import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.CacheMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
/**
* Ensures that the FTS indexing picks up on any outstanding documents that
* require indexing.
* <p>
* This component must be used as a singleton (one per VM) and may only be
* called to reindex once. It will start a thread that processes all available
* transactions and keeps checking to ensure that the index is up to date with
* the latest database changes.
* <p>
* <b>The following points are important:</b>
* <ul>
* <li>
* By default, the Hibernate L2 cache is used during processing.
* This can be disabled by either disabling the L2 cache globally
* for the server (not recommended) or by setting the
* {@link #setL2CacheMode(String) l2CacheMode} property. If the
* database is static then the L2 cache usage can be set to use
* the <code>NORMAL</code> mode. <code>REFRESH</code> should be
* used where the server will still be accessed from some clients
* despite the database changing.
* </li>
* <li>
* This process should not run continuously on a live
* server as it would be performing unecessary work.
* If it was left running, however, it would not
* lead to data corruption or such-like. Use the
* {@link #setRunContinuously(boolean) runContinuously} property
* to change this behaviour.
* </li>
* </ul>
*
* @author Derek Hulley
*/
public class FullIndexRecoveryComponent extends HibernateDaoSupport implements IndexRecovery
{
public static final String QUERY_GET_NEXT_CHANGE_TXN_IDS = "node.GetNextChangeTxnIds";
public static final String QUERY_GET_CHANGED_NODE_STATUSES = "node.GetChangedNodeStatuses";
public static final String QUERY_GET_CHANGED_NODE_STATUSES_COUNT = "node.GetChangedNodeStatusesCount";
private static final String START_TXN_ID = "000";
private static Log logger = LogFactory.getLog(FullIndexRecoveryComponent.class);
/** ensures that this process is kicked off once per VM */
private static boolean started = false;
/** The current transaction ID being processed */
private static String currentTxnId = START_TXN_ID;
/** kept to notify the thread that it should quite */
private boolean killThread = false;
/** provides transactions to atomically index each missed transaction */
private TransactionService transactionService;
/** the component to index the node hierarchy */
private Indexer indexer;
/** the FTS indexer that we will prompt to pick up on any un-indexed text */
private FullTextSearchIndexer ftsIndexer;
/** the component providing searches of the indexed nodes */
private SearchService searcher;
/** the component giving direct access to <b>node</b> instances */
private NodeService nodeService;
/** the stores to reindex */
private List<StoreRef> storeRefs;
/** set this to run the index recovery component */
private boolean executeFullRecovery;
/** set this on to keep checking for new transactions and never stop */
private boolean runContinuously;
/** set the time to wait between checking indexes */
private long waitTime;
/** controls how the L2 cache is used */
private CacheMode l2CacheMode;
/**
* @return Returns the ID of the current (or last) transaction processed
*/
public static String getCurrentTransactionId()
{
return currentTxnId;
}
public FullIndexRecoveryComponent()
{
this.storeRefs = new ArrayList<StoreRef>(2);
this.killThread = false;
this.executeFullRecovery = false;
this.runContinuously = false;
this.waitTime = 1000L;
this.l2CacheMode = CacheMode.REFRESH;
// ensure that we kill the thread when the VM is shutting down
Runnable shutdownRunnable = new Runnable()
{
public void run()
{
killThread = true;
};
};
Thread shutdownThread = new Thread(shutdownRunnable);
Runtime.getRuntime().addShutdownHook(shutdownThread);
}
/**
* @return Returns true if the component has already been started
*/
public static boolean isStarted()
{
return started;
}
/**
* @param transactionService provide transactions to index each missed transaction
*/
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
/**
* @param indexer the indexer that will be index
*/
public void setIndexer(Indexer indexer)
{
this.indexer = indexer;
}
/**
* @param ftsIndexer the FTS background indexer
*/
public void setFtsIndexer(FullTextSearchIndexer ftsIndexer)
{
this.ftsIndexer = ftsIndexer;
}
/**
* @param searcher component providing index searches
*/
public void setSearcher(SearchService searcher)
{
this.searcher = searcher;
}
/**
* @param nodeService provides information about nodes for indexing
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Set the stores that need reindexing
*
* @param storeRefStrings a list of strings representing store references
*/
public void setStores(List<String> storeRefStrings)
{
storeRefs.clear();
for (String storeRefStr : storeRefStrings)
{
StoreRef storeRef = new StoreRef(storeRefStr);
storeRefs.add(storeRef);
}
}
/**
* Set this to <code>true</code> to initiate the full index recovery.
* <p>
* This used to default to <code>true</code> but is now false. Set this
* if the potentially long-running process of checking and fixing the
* indexes must be started.
*
* @param executeFullRecovery
*/
public void setExecuteFullRecovery(boolean executeFullRecovery)
{
this.executeFullRecovery = executeFullRecovery;
}
/**
* Set this to ensure that the process continuously checks for new transactions.
* If not, it will permanently terminate once it catches up with the current
* transactions.
*
* @param runContinuously true to never cease looking for new transactions
*/
public void setRunContinuously(boolean runContinuously)
{
this.runContinuously = runContinuously;
}
/**
* Set the time to wait between checking for new transaction changes in the database.
*
* @param waitTime the time to wait in milliseconds
*/
public void setWaitTime(long waitTime)
{
this.waitTime = waitTime;
}
/**
* Set the hibernate cache mode by name
*
* @see org.hibernate.CacheMode
*/
public void setL2CacheMode(String l2CacheModeStr)
{
if (l2CacheModeStr.equals("GET"))
{
l2CacheMode = CacheMode.GET;
}
else if (l2CacheModeStr.equals("IGNORE"))
{
l2CacheMode = CacheMode.IGNORE;
}
else if (l2CacheModeStr.equals("NORMAL"))
{
l2CacheMode = CacheMode.NORMAL;
}
else if (l2CacheModeStr.equals("PUT"))
{
l2CacheMode = CacheMode.PUT;
}
else if (l2CacheModeStr.equals("REFRESH"))
{
l2CacheMode = CacheMode.REFRESH;
}
else
{
throw new IllegalArgumentException("Unrecognised Hibernate L2 cache mode: " + l2CacheModeStr);
}
}
/**
* Ensure that the index is up to date with the current state of the persistence layer.
* The full list of unique transaction change IDs is retrieved and used to detect
* which are not present in the index. All the node changes and deletions for the
* remaining transactions are then indexed.
*/
public synchronized void reindex()
{
if (FullIndexRecoveryComponent.started)
{
throw new AlfrescoRuntimeException
("Only one FullIndexRecoveryComponent may be used per VM and it may only be called once");
}
// ensure that we don't redo this work
FullIndexRecoveryComponent.started = true;
// work to mark the stores for full text reindexing
TransactionWork<Object> ftsReindexWork = new TransactionWork<Object>()
{
public Object doWork()
{
// reindex each store
for (StoreRef storeRef : storeRefs)
{
// check if the store exists
if (!nodeService.exists(storeRef))
{
// store does not exist
if (logger.isDebugEnabled())
{
logger.debug("Skipping reindex of non-existent store: " + storeRef);
}
continue;
}
// prompt FTS to reindex the store
ftsIndexer.requiresIndex(storeRef);
}
// done
if (logger.isDebugEnabled())
{
logger.debug("Prompted FTS index on stores: " + storeRefs);
}
return null;
}
};
TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, ftsReindexWork);
// start full index recovery, if necessary
if (!this.executeFullRecovery)
{
if (logger.isDebugEnabled())
{
logger.debug("Full index recovery is off - quitting");
}
}
else
{
// set the state of the reindex
FullIndexRecoveryComponent.currentTxnId = START_TXN_ID;
// start a stateful thread that will begin processing the reindexing the transactions
Runnable runnable = new ReindexRunner();
Thread reindexThread = new Thread(runnable);
// make it a daemon thread
reindexThread.setDaemon(true);
// it should not be a high priority
reindexThread.setPriority(Thread.MIN_PRIORITY);
// start it
reindexThread.start();
if (logger.isDebugEnabled())
{
logger.debug("Full index recovery thread started: \n" +
" continuous: " + runContinuously + "\n" +
" stores: " + storeRefs);
}
}
}
/**
* Stateful thread runnable that executes reindex calls.
*
* @see FullIndexRecoveryComponent#reindexNodes()
*
* @author Derek Hulley
*/
private class ReindexRunner implements Runnable
{
public void run()
{
// keep this thread going permanently
while (!killThread)
{
try
{
// reindex nodes
List<String> txnsIndexed = FullIndexRecoveryComponent.this.reindexNodes();
// reindex missing content
@SuppressWarnings("unused")
int missingContentCount = FullIndexRecoveryComponent.this.reindexMissingContent();
// check if the process should terminate
if (txnsIndexed.size() == 0 && !runContinuously)
{
// the thread has caught up with all the available work and should not
// run continuously
if (logger.isDebugEnabled())
{
logger.debug("Thread quitting - no more available indexing to do: \n" +
" last txn: " + FullIndexRecoveryComponent.getCurrentTransactionId());
}
break;
}
// brief pause
synchronized(FullIndexRecoveryComponent.this)
{
FullIndexRecoveryComponent.this.wait(waitTime);
}
}
catch (InterruptedException e)
{
// ignore
}
catch (Throwable e)
{
if (killThread)
{
// the shutdown may have caused the exception - ignore it
}
else
{
// we are still a go; report it
logger.error("Reindex failure", e);
}
}
}
}
}
/**
* @return Returns the number of documents reindexed
*/
private int reindexMissingContent()
{
int count = 0;
for (StoreRef storeRef : storeRefs)
{
count += reindexMissingContent(storeRef);
}
return count;
}
/**
* @param storeRef the store to check for missing content
* @return Returns the number of documents reindexed
*/
private int reindexMissingContent(StoreRef storeRef)
{
SearchParameters sp = new SearchParameters();
sp.addStore(storeRef);
// search for it in the index
String query = "TEXT:" + LuceneIndexerImpl.NOT_INDEXED_CONTENT_MISSING;
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery(query);
ResultSet results = null;
try
{
results = searcher.query(sp);
int count = 0;
// loop over the results and get the details of the nodes that have missing content
List<ChildAssociationRef> assocRefs = results.getChildAssocRefs();
for (ChildAssociationRef assocRef : assocRefs)
{
final NodeRef childNodeRef = assocRef.getChildRef();
// prompt for a reindex - it might fail again, but we just keep plugging away
TransactionWork<Object> reindexWork = new TransactionWork<Object>()
{
public Object doWork()
{
indexer.updateNode(childNodeRef);
return null;
}
};
TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork);
count++;
}
// done
if (logger.isDebugEnabled())
{
logger.debug("Reindexed missing content: \n" +
" store: " + storeRef + "\n" +
" node count: " + count);
}
return count;
}
finally
{
if (results != null)
{
results.close();
}
}
}
/**
* @return Returns the transaction ID just reindexed, i.e. where some work was performed
*/
private List<String> reindexNodes()
{
// get a list of all transactions still requiring a check
List<String> txnsToCheck = getNextChangeTxnIds(FullIndexRecoveryComponent.currentTxnId);
// loop over each transaction
for (String changeTxnId : txnsToCheck)
{
reindexNodes(changeTxnId);
}
// done
return txnsToCheck;
}
/**
* Reindexes changes specific to the change transaction ID.
* <p>
* <b>All exceptions are absorbed.</b>
*/
private void reindexNodes(final String changeTxnId)
{
/*
* This must execute each within its own transaction.
* The cache size is therefore not an issue.
*/
TransactionWork<Object> reindexWork = new TransactionWork<Object>()
{
public Object doWork() throws Exception
{
// perform the work in a Hibernate callback
HibernateCallback callback = new ReindexCallback(changeTxnId);
getHibernateTemplate().execute(callback);
// done
return null;
}
};
try
{
TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork);
}
catch (Throwable e)
{
logger.error("Transaction reindex failed: \n" +
" txn: " + changeTxnId,
e);
}
finally
{
// Up the current transaction now, in case the process fails at this point.
// This will prevent the transaction from being processed again.
// This applies to failures as well, which should be dealt with externally
// and having the entire process start again, e.g. such as a system reboot
currentTxnId = changeTxnId;
}
}
/**
* Stateful inner class that implements a single reindex call for a given store
* and transaction.
* <p>
* It must be called within its own transaction.
*
* @author Derek Hulley
*/
private class ReindexCallback implements HibernateCallback
{
private final String changeTxnId;
public ReindexCallback(String changeTxnId)
{
this.changeTxnId = changeTxnId;
}
/**
* Changes the L2 cache usage before reindexing for each store
*
* @see #reindexNodes(StoreRef, String)
*/
public Object doInHibernate(Session session)
{
// set the way the L2 cache is used
getSession().setCacheMode(l2CacheMode);
// reindex each store
for (StoreRef storeRef : storeRefs)
{
if (!nodeService.exists(storeRef))
{
// the store is not present
continue;
}
// reindex for store
reindexNodes(storeRef, changeTxnId);
}
// done
return null;
}
private void reindexNodes(StoreRef storeRef, String changeTxnId)
{
// check if we need to perform this operation
SearchParameters sp = new SearchParameters();
sp.addStore(storeRef);
// search for it in the index
String query = "TX:\"" + changeTxnId + "\"";
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery(query);
ResultSet results = null;
try
{
results = searcher.query(sp);
// did the index have any of these changes?
if (results.length() > 0)
{
// the transaction has an entry in the index - assume that it was
// atomically correct
if (logger.isDebugEnabled())
{
logger.debug("Transaction present in index - no indexing required: \n" +
" store: " + storeRef + "\n" +
" txn: " + changeTxnId);
}
return;
}
}
finally
{
if (results != null)
{
results.close();
}
}
// the index has no record of this
// were there any changes, or is it all just deletions?
int changedCount = getChangedNodeStatusesCount(storeRef, changeTxnId);
if (changedCount == 0)
{
// no nodes were changed in the transaction, i.e. they are only deletions
// the index is quite right not to have any entries for the transaction
if (logger.isDebugEnabled())
{
logger.debug("Transaction only has deletions - no indexing required: \n" +
" store: " + storeRef + "\n" +
" txn: " + changeTxnId);
}
return;
}
// process the deletions relevant to the txn and the store
List<NodeStatus> deletedNodeStatuses = getDeletedNodeStatuses(storeRef, changeTxnId);
for (NodeStatus status : deletedNodeStatuses)
{
NodeRef nodeRef = new NodeRef(storeRef, status.getKey().getGuid());
// only the child node ref is relevant
ChildAssociationRef assocRef = new ChildAssociationRef(
ContentModel.ASSOC_CHILDREN,
null,
null,
nodeRef);
indexer.deleteNode(assocRef);
}
// process additions
List<NodeStatus> changedNodeStatuses = getChangedNodeStatuses(storeRef, changeTxnId);
for (NodeStatus status : changedNodeStatuses)
{
NodeRef nodeRef = new NodeRef(storeRef, status.getKey().getGuid());
// get the primary assoc for the node
ChildAssociationRef primaryAssocRef = nodeService.getPrimaryParent(nodeRef);
// reindex
indexer.createNode(primaryAssocRef);
}
// done
if (logger.isDebugEnabled())
{
logger.debug("Transaction reindexed: \n" +
" store: " + storeRef + "\n" +
" txn: " + changeTxnId + "\n" +
" deletions: " + deletedNodeStatuses.size() + "\n" +
" modifications: " + changedNodeStatuses.size());
}
}
};
/**
* Retrieve all transaction IDs that are greater than the given transaction ID.
*
* @param currentTxnId the transaction ID that must be less than all returned results
* @return Returns an ordered list of transaction IDs
*/
@SuppressWarnings("unchecked")
public List<String> getNextChangeTxnIds(final String currentTxnId)
{
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
Query query = session.getNamedQuery(QUERY_GET_NEXT_CHANGE_TXN_IDS);
query.setString("currentTxnId", currentTxnId)
.setReadOnly(true);
return query.list();
}
};
List<String> queryResults = (List<String>) getHibernateTemplate().execute(callback);
// done
return queryResults;
}
@SuppressWarnings("unchecked")
public int getChangedNodeStatusesCount(final StoreRef storeRef, final String changeTxnId)
{
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
Query query = session.getNamedQuery(QUERY_GET_CHANGED_NODE_STATUSES_COUNT);
query.setBoolean("deleted", false)
.setString("storeProtocol", storeRef.getProtocol())
.setString("storeIdentifier", storeRef.getIdentifier())
.setString("changeTxnId", changeTxnId)
.setReadOnly(true);
return query.uniqueResult();
}
};
Integer changeCount = (Integer) getHibernateTemplate().execute(callback);
// done
return changeCount.intValue();
}
@SuppressWarnings("unchecked")
public List<NodeStatus> getChangedNodeStatuses(final StoreRef storeRef, final String changeTxnId)
{
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
Query query = session.getNamedQuery(QUERY_GET_CHANGED_NODE_STATUSES);
query.setBoolean("deleted", false)
.setString("storeProtocol", storeRef.getProtocol())
.setString("storeIdentifier", storeRef.getIdentifier())
.setString("changeTxnId", changeTxnId)
.setReadOnly(true);
return query.list();
}
};
List<NodeStatus> queryResults = (List) getHibernateTemplate().execute(callback);
// done
return queryResults;
}
@SuppressWarnings("unchecked")
public List<NodeStatus> getDeletedNodeStatuses(final StoreRef storeRef, final String changeTxnId)
{
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
Query query = session.getNamedQuery(QUERY_GET_CHANGED_NODE_STATUSES);
query.setBoolean("deleted", true)
.setString("storeProtocol", storeRef.getProtocol())
.setString("storeIdentifier", storeRef.getIdentifier())
.setString("changeTxnId", changeTxnId)
.setReadOnly(true);
return query.list();
}
};
List<NodeStatus> queryResults = (List) getHibernateTemplate().execute(callback);
// done
return queryResults;
}
}

View File

@@ -0,0 +1,166 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.node.index;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.Indexer;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidStoreRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ApplicationContext;
/**
* Checks that full index recovery is possible
*
* @author Derek Hulley
*/
public class FullIndexRecoveryComponentTest extends TestCase
{
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private TransactionService transactionService;
private FullIndexRecoveryComponent indexRecoverer;
private NodeService nodeService;
private TransactionService txnService;
private Indexer indexer;
private List<StoreRef> storeRefs;
public void setUp() throws Exception
{
transactionService = (TransactionService) ctx.getBean("transactionComponent");
indexRecoverer = (FullIndexRecoveryComponent) ctx.getBean("indexRecoveryComponent");
txnService = (TransactionService) ctx.getBean("transactionComponent");
nodeService = (NodeService) ctx.getBean("nodeService");
indexer = (Indexer) ctx.getBean("indexerComponent");
// create 2 stores
TransactionWork<List<StoreRef>> createStoresWork = new TransactionWork<List<StoreRef>>()
{
public List<StoreRef> doWork() throws Exception
{
List<StoreRef> storeRefs = new ArrayList<StoreRef>(2);
storeRefs.add(nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, getName() + System.nanoTime()));
storeRefs.add(nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, getName() + System.nanoTime()));
return storeRefs;
}
};
storeRefs = TransactionUtil.executeInUserTransaction(transactionService, createStoresWork);
}
public void testNothing() throws Exception
{
}
public void xtestReindexing() throws Exception
{
// don't do anything if the component has already started
if (FullIndexRecoveryComponent.isStarted())
{
return;
}
// deletes a content node from the index
final List<String> storeRefStrings = new ArrayList<String>(2);
TransactionWork<String> dropNodeIndexWork = new TransactionWork<String>()
{
public String doWork()
{
// create a node in each store and drop it from the index
for (StoreRef storeRef : storeRefs)
{
try
{
NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
ChildAssociationRef assocRef = nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.ALFRESCO_URI, "unindexedChild" + System.currentTimeMillis()),
ContentModel.TYPE_BASE);
// this will have indexed it, so remove it from the index
indexer.deleteNode(assocRef);
// make the string version of the storeRef
storeRefStrings.add(storeRef.toString());
}
catch (InvalidStoreRefException e)
{
// just ignore stores that are invalid
}
}
return AlfrescoTransactionSupport.getTransactionId();
}
};
// create un-indexed nodes
String txnId = TransactionUtil.executeInNonPropagatingUserTransaction(txnService, dropNodeIndexWork);
indexRecoverer.setExecuteFullRecovery(true);
indexRecoverer.setStores(storeRefStrings);
// reindex
indexRecoverer.reindex();
// check that reindexing fails
try
{
indexRecoverer.reindex();
fail("Reindexer failed to prevent reindex from being called twice");
}
catch (RuntimeException e)
{
// expected
}
// loop for some time, giving it a chance to do its thing
String lastProcessedTxnId = null;
for (int i = 0; i < 60; i++)
{
lastProcessedTxnId = FullIndexRecoveryComponent.getCurrentTransactionId();
if (lastProcessedTxnId.equals(txnId))
{
break;
}
// wait for a second
synchronized(this)
{
this.wait(1000L);
}
}
// check that the index was recovered
assertEquals("Index transaction not up to date", txnId, lastProcessedTxnId);
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.jaas;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.LanguageCallback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.RealmCallback;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
/**
* JAAS based authentication
*
* The user name and password are picked up from login.
*
* The other configurable parameters are:
* realm - the authentication realm if required,
* and the entry name to use from the login context.
*
* You will need to be familiar with the JAAS authentication process to set this up.
*
* In summary you will need to configure java.security (in the lib/security directory of the jre you are using)
* to find a jaas configuration.
*
* This entry could be used if you want to put the login configuration in the same place (in the lib/security directory of the jre you are using)
*
* <code>
* login.config.url.1=file:${java.home}/lib/security/java.login.config
* </code>
*
* Example configuration entries for Kerberos would be:
*
* <code>
* Alfresco {
* com.sun.security.auth.module.Krb5LoginModule sufficient;
* };
*
* com.sun.net.ssl.client {
* com.sun.security.auth.module.Krb5LoginModule sufficient;
* };
*
* other {
* com.sun.security.auth.module.Krb5LoginModule sufficient;
* };
* </code>
*
* This sets up authentication using Kerberos for Alfresco and some defaults that would use the same mechanism if sasl failed for example.
*
* You could use kerberos and LDAP combined against an Active Directory server.
*
* @author Andy Hind
*/
public class JAASAuthenticationComponent extends AbstractAuthenticationComponent
{
/**
* A key into the login config that defines the authentication mechamisms required.
*/
private String jaasConfigEntryName = "Alfresco";
/**
* A default realm
*/
private String realm = null;
public JAASAuthenticationComponent()
{
super();
}
// Springification
public void setJaasConfigEntryName(String jaasConfigEntryName)
{
this.jaasConfigEntryName = jaasConfigEntryName;
}
public void setRealm(String realm)
{
this.realm = realm;
}
/**
* Jaas does not support guest login
*/
@Override
protected boolean implementationAllowsGuestLogin()
{
return false;
}
/**
* Implement Authentication
*/
public void authenticate(String userName, char[] password) throws AuthenticationException
{
LoginContext lc;
try
{
lc = new LoginContext(jaasConfigEntryName, new SimpleCallback(userName, realm, password));
}
catch (LoginException e)
{
throw new AuthenticationException("Login Failed", e);
}
try
{
lc.login();
// Login has gone through OK, set up the acegi context
setCurrentUser(userName);
}
catch (LoginException e)
{
throw new AuthenticationException("Login Failed", e);
}
}
/**
* Simple call back class to support the common requirements.
*
* @author Andy Hind
*/
private static class SimpleCallback implements CallbackHandler
{
String userName;
String realm;
char[] password;
SimpleCallback(String userName, String realm, char[] password)
{
this.userName = userName;
this.realm = realm;
this.password = password;
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
{
for (int i = 0; i < callbacks.length; i++)
{
if (callbacks[i] instanceof AuthorizeCallback)
{
AuthorizeCallback cb = (AuthorizeCallback) callbacks[i];
cb.setAuthorized(false);
}
else if (callbacks[i] instanceof LanguageCallback)
{
LanguageCallback cb = (LanguageCallback) callbacks[i];
cb.setLocale(I18NUtil.getLocale());
}
else if (callbacks[i] instanceof NameCallback)
{
NameCallback cb = (NameCallback) callbacks[i];
cb.setName(userName);
}
else if (callbacks[i] instanceof PasswordCallback)
{
PasswordCallback cb = (PasswordCallback) callbacks[i];
cb.setPassword(password);
}
else if (callbacks[i] instanceof RealmCallback)
{
RealmCallback cb = (RealmCallback) callbacks[i];
cb.setText(realm);
}
else
{
throw new UnsupportedCallbackException(callbacks[i]);
}
}
}
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ldap;
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;
import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
/**
* Currently expects the cn name of the user which is in a fixed location.
*
* @author Andy Hind
*/
public class LDAPAuthenticationComponentImpl extends AbstractAuthenticationComponent
{
private String userNameFormat;
private LDAPInitialDirContextFactory ldapInitialContextFactory;
public LDAPAuthenticationComponentImpl()
{
super();
}
public void setLDAPInitialDirContextFactory(LDAPInitialDirContextFactory ldapInitialDirContextFactory)
{
this.ldapInitialContextFactory = ldapInitialDirContextFactory;
}
public void setUserNameFormat(String userNameFormat)
{
this.userNameFormat = userNameFormat;
}
/**
* Implement the authentication method
*/
public void authenticate(String userName, char[] password) throws AuthenticationException
{
InitialDirContext ctx = null;
try
{
ctx = ldapInitialContextFactory.getInitialDirContext(String.format(userNameFormat, new Object[]{userName}), new String(password));
// Authentication has been successful.
// Set the current user, they are now authenticated.
setCurrentUser(userName);
}
finally
{
if(ctx != null)
{
try
{
ctx.close();
}
catch (NamingException e)
{
clearCurrentSecurityContext();
throw new AuthenticationException("Failed to close connection", e);
}
}
}
}
@Override
protected boolean implementationAllowsGuestLogin()
{
InitialDirContext ctx = null;
try
{
ctx = ldapInitialContextFactory.getDefaultIntialDirContext();
return true;
}
catch(Exception e)
{
return false;
}
finally
{
if(ctx != null)
{
try
{
ctx.close();
}
catch (NamingException e)
{
throw new AuthenticationException("Failed to close connection", e);
}
}
}
}
}

View File

@@ -0,0 +1,695 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ldap;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.importer.ExportSource;
import org.alfresco.repo.importer.ExportSourceImporterException;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.EqualsHelper;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
public class LDAPGroupExportSource implements ExportSource, InitializingBean
{
private static Log s_logger = LogFactory.getLog(LDAPGroupExportSource.class);
private String groupQuery = "(objectclass=groupOfNames)";
private String searchBase;
private String groupIdAttributeName = "cn";
private String userIdAttributeName = "uid";
private String groupType = "groupOfNames";
private String personType = "inetOrgPerson";
private LDAPInitialDirContextFactory ldapInitialContextFactory;
private NamespaceService namespaceService;
private String memberAttribute = "member";
private boolean errorOnMissingMembers = false;
private QName viewRef;
private QName viewId;
private QName viewAssociations;
private QName childQName;
private QName viewValueQName;
private QName viewIdRef;
public LDAPGroupExportSource()
{
super();
}
public void setGroupIdAttributeName(String groupIdAttributeName)
{
this.groupIdAttributeName = groupIdAttributeName;
}
public void setGroupQuery(String groupQuery)
{
this.groupQuery = groupQuery;
}
public void setGroupType(String groupType)
{
this.groupType = groupType;
}
public void setLDAPInitialDirContextFactory(LDAPInitialDirContextFactory ldapInitialDirContextFactory)
{
this.ldapInitialContextFactory = ldapInitialDirContextFactory;
}
public void setMemberAttribute(String memberAttribute)
{
this.memberAttribute = memberAttribute;
}
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
public void setPersonType(String personType)
{
this.personType = personType;
}
public void setSearchBase(String searchBase)
{
this.searchBase = searchBase;
}
public void setUserIdAttributeName(String userIdAttributeName)
{
this.userIdAttributeName = userIdAttributeName;
}
public void setErrorOnMissingMembers(boolean errorOnMissingMembers)
{
this.errorOnMissingMembers = errorOnMissingMembers;
}
public void generateExport(XMLWriter writer)
{
HashSet<Group> rootGroups = new HashSet<Group>();
HashMap<String, Group> lookup = new HashMap<String, Group>();
HashSet<SecondaryLink> secondaryLinks = new HashSet<SecondaryLink>();
buildGroupsAndRoots(rootGroups, lookup, secondaryLinks);
buildXML(rootGroups, lookup, secondaryLinks, writer);
}
private void buildXML(HashSet<Group> rootGroups, HashMap<String, Group> lookup,
HashSet<SecondaryLink> secondaryLinks, XMLWriter writer)
{
Collection<String> prefixes = namespaceService.getPrefixes();
QName childQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "childName", namespaceService);
try
{
AttributesImpl attrs = new AttributesImpl();
attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, childQName.getLocalName(), childQName
.toPrefixString(), null, ContentModel.TYPE_PERSON.toPrefixString(namespaceService));
writer.startDocument();
for (String prefix : prefixes)
{
if (!prefix.equals("xml"))
{
String uri = namespaceService.getNamespaceURI(prefix);
writer.startPrefixMapping(prefix, uri);
}
}
writer.startElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view",
NamespaceService.REPOSITORY_VIEW_PREFIX + ":" + "view", new AttributesImpl());
// Create group structure
for (Group group : rootGroups)
{
addRootGroup(lookup, group, writer);
}
// Create secondary links.
for (SecondaryLink sl : secondaryLinks)
{
addSecondarylink(lookup, sl, writer);
}
for (String prefix : prefixes)
{
if (!prefix.equals("xml"))
{
writer.endPrefixMapping(prefix);
}
}
writer.endElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", NamespaceService.REPOSITORY_VIEW_PREFIX
+ ":" + "view");
writer.endDocument();
}
catch (SAXException e)
{
throw new ExportSourceImporterException("Failed to create file for import.", e);
}
}
private void addSecondarylink(HashMap<String, Group> lookup, SecondaryLink sl, XMLWriter writer)
throws SAXException
{
String fromId = lookup.get(sl.from).guid;
String toId = lookup.get(sl.to).guid;
AttributesImpl attrs = new AttributesImpl();
attrs.addAttribute(viewIdRef.getNamespaceURI(), viewIdRef.getLocalName(), viewIdRef.toPrefixString(), null, fromId);
writer.startElement(viewRef.getNamespaceURI(), viewRef.getLocalName(),
viewRef.toPrefixString(namespaceService), attrs);
writer.startElement(viewAssociations.getNamespaceURI(), viewAssociations.getLocalName(), viewAssociations
.toPrefixString(namespaceService), new AttributesImpl());
writer.startElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(),
ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService), new AttributesImpl());
AttributesImpl attrsRef = new AttributesImpl();
attrsRef.addAttribute(viewIdRef.getNamespaceURI(), viewIdRef.getLocalName(), viewIdRef.toPrefixString(), null, toId);
attrsRef.addAttribute(childQName.getNamespaceURI(), childQName.getLocalName(), childQName.toPrefixString(),
null, QName.createQName(ContentModel.USER_MODEL_URI, sl.to).toPrefixString(namespaceService));
writer.startElement(viewRef.getNamespaceURI(), viewRef.getLocalName(),
viewRef.toPrefixString(namespaceService), attrsRef);
writer.endElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), viewRef.toPrefixString(namespaceService));
writer.endElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(),
ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService));
writer.endElement(viewAssociations.getNamespaceURI(), viewAssociations.getLocalName(), viewAssociations
.toPrefixString(namespaceService));
writer.endElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), viewRef.toPrefixString(namespaceService));
}
private void addRootGroup(HashMap<String, Group> lookup, Group group, XMLWriter writer) throws SAXException
{
AttributesImpl attrs = new AttributesImpl();
attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, childQName.getLocalName(), childQName
.toPrefixString(), null, QName.createQName(ContentModel.USER_MODEL_URI, group.gid).toPrefixString(
namespaceService));
attrs.addAttribute(viewId.getNamespaceURI(), viewId.getLocalName(), viewId
.toPrefixString(), null, group.guid);
writer.startElement(ContentModel.TYPE_AUTHORITY_CONTAINER.getNamespaceURI(),
ContentModel.TYPE_AUTHORITY_CONTAINER.getLocalName(), ContentModel.TYPE_AUTHORITY_CONTAINER
.toPrefixString(namespaceService), attrs);
writer.startElement(ContentModel.PROP_AUTHORITY_NAME.getNamespaceURI(), ContentModel.PROP_AUTHORITY_NAME
.getLocalName(), ContentModel.PROP_AUTHORITY_NAME.toPrefixString(namespaceService),
new AttributesImpl());
writer.characters(group.gid.toCharArray(), 0, group.gid.length());
writer.endElement(ContentModel.PROP_AUTHORITY_NAME.getNamespaceURI(), ContentModel.PROP_AUTHORITY_NAME
.getLocalName(), ContentModel.PROP_AUTHORITY_NAME.toPrefixString(namespaceService));
if (group.members.size() > 0)
{
writer.startElement(ContentModel.PROP_MEMBERS.getNamespaceURI(), ContentModel.PROP_MEMBERS.getLocalName(),
ContentModel.PROP_MEMBERS.toPrefixString(namespaceService), new AttributesImpl());
for (String member : group.members)
{
writer.startElement(viewValueQName.getNamespaceURI(), viewValueQName.getLocalName(), viewValueQName
.toPrefixString(namespaceService), new AttributesImpl());
writer.characters(member.toCharArray(), 0, member.length());
writer.endElement(viewValueQName.getNamespaceURI(), viewValueQName.getLocalName(), viewValueQName
.toPrefixString(namespaceService));
}
writer.endElement(ContentModel.PROP_MEMBERS.getNamespaceURI(), ContentModel.PROP_MEMBERS.getLocalName(),
ContentModel.PROP_MEMBERS.toPrefixString(namespaceService));
}
for (Group child : group.children)
{
addgroup(lookup, child, writer);
}
writer.endElement(ContentModel.TYPE_AUTHORITY_CONTAINER.getNamespaceURI(),
ContentModel.TYPE_AUTHORITY_CONTAINER.getLocalName(), ContentModel.TYPE_AUTHORITY_CONTAINER
.toPrefixString(namespaceService));
}
private void addgroup(HashMap<String, Group> lookup, Group group, XMLWriter writer) throws SAXException
{
AttributesImpl attrs = new AttributesImpl();
writer.startElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(),
ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService), attrs);
addRootGroup(lookup, group, writer);
writer.endElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(),
ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService));
}
private void buildGroupsAndRoots(HashSet<Group> rootGroups, HashMap<String, Group> lookup,
HashSet<SecondaryLink> secondaryLinks)
{
InitialDirContext ctx = null;
try
{
ctx = ldapInitialContextFactory.getDefaultIntialDirContext();
SearchControls userSearchCtls = new SearchControls();
userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration searchResults = ctx.search(searchBase, groupQuery, userSearchCtls);
while (searchResults.hasMoreElements())
{
SearchResult result = (SearchResult) searchResults.next();
Attributes attributes = result.getAttributes();
Attribute gidAttribute = attributes.get(groupIdAttributeName);
if(gidAttribute == null)
{
throw new ExportSourceImporterException("Group returned by group search does not have mandatory group id attribute "+attributes);
}
String gid = (String) gidAttribute.get(0);
Group group = lookup.get(gid);
if (group == null)
{
group = new Group(gid);
lookup.put(group.gid, group);
rootGroups.add(group);
}
Attribute memAttribute = attributes.get(memberAttribute);
// check for null
if (memAttribute != null)
{
for (int i = 0; i < memAttribute.size(); i++)
{
String attribute = (String) memAttribute.get(i);
if (attribute != null)
{
group.distinguishedNames.add(attribute);
}
}
}
}
if (s_logger.isDebugEnabled())
{
s_logger.debug("Found " + lookup.size());
}
for (Group group : lookup.values())
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("Linking " + group.gid);
}
for (String dn : group.distinguishedNames)
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("... " + dn);
}
String id;
Boolean isGroup = null;
SearchControls memberSearchCtls = new SearchControls();
memberSearchCtls.setSearchScope(SearchControls.OBJECT_SCOPE);
NamingEnumeration memberSearchResults;
try
{
memberSearchResults = ctx.search(dn, "(objectClass=*)", memberSearchCtls);
}
catch (NamingException e)
{
if (errorOnMissingMembers)
{
throw e;
}
s_logger.warn("Failed to resolve distinguished name: " + dn);
continue;
}
while (memberSearchResults.hasMoreElements())
{
id = null;
SearchResult result;
try
{
result = (SearchResult) memberSearchResults.next();
}
catch (NamingException e)
{
if (errorOnMissingMembers)
{
throw e;
}
s_logger.warn("Failed to resolve distinguished name: " + dn);
continue;
}
Attributes attributes = result.getAttributes();
Attribute objectclass = attributes.get("objectclass");
if(objectclass == null)
{
throw new ExportSourceImporterException("Failed to find attribute objectclass for DN "+dn);
}
for (int i = 0; i < objectclass.size(); i++)
{
String testType;
try
{
testType = (String) objectclass.get(i);
}
catch (NamingException e)
{
if (errorOnMissingMembers)
{
throw e;
}
s_logger.warn("Failed to resolve object class attribute for distinguished name: " + dn);
continue;
}
if (testType.equals(groupType))
{
isGroup = true;
try
{
Attribute groupIdAttribute = attributes.get(groupIdAttributeName);
if(groupIdAttribute == null)
{
throw new ExportSourceImporterException("Group missing group id attribute DN ="+dn + " att = "+groupIdAttributeName);
}
id = (String) groupIdAttribute.get(0);
}
catch (NamingException e)
{
if (errorOnMissingMembers)
{
throw e;
}
s_logger.warn("Failed to resolve group identifier "
+ groupIdAttributeName + " for distinguished name: " + dn);
id = "Unknown sub group";
}
break;
}
else if (testType.equals(personType))
{
isGroup = false;
try
{
Attribute userIdAttribute = attributes.get(userIdAttributeName);
if(userIdAttribute == null)
{
throw new ExportSourceImporterException("User missing user id attribute DN ="+dn + " att = "+userIdAttributeName);
}
id = (String) userIdAttribute.get(0);
}
catch (NamingException e)
{
if (errorOnMissingMembers)
{
throw e;
}
s_logger.warn("Failed to resolve group identifier "
+ userIdAttributeName + " for distinguished name: " + dn);
id = "Unknown member";
}
break;
}
}
if (id != null)
{
if (isGroup == null)
{
throw new ExportSourceImporterException("Type not recognised for DN"+dn);
}
else if (isGroup)
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("... is sub group");
}
Group child = lookup.get("GROUP_" + id);
if (child == null)
{
throw new ExportSourceImporterException("Failed to find child group " + id);
}
if (rootGroups.contains(child))
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("... Primary created from "
+ group.gid + " to " + child.gid);
}
group.children.add(child);
rootGroups.remove(child);
}
else
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("... Secondary created from "
+ group.gid + " to " + child.gid);
}
secondaryLinks.add(new SecondaryLink(group.gid, child.gid));
}
}
else
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("... is member");
}
group.members.add(id);
}
}
}
}
}
if (s_logger.isDebugEnabled())
{
s_logger.debug("Top " + rootGroups.size());
s_logger.debug("Secondary " + secondaryLinks.size());
}
}
catch (NamingException e)
{
throw new ExportSourceImporterException("Failed to import people.", e);
}
finally
{
if (ctx != null)
{
try
{
ctx.close();
}
catch (NamingException e)
{
throw new ExportSourceImporterException("Failed to import people.", e);
}
}
}
}
private static class Group
{
String gid;
String guid = GUID.generate();
HashSet<Group> children = new HashSet<Group>();
HashSet<String> members = new HashSet<String>();
HashSet<String> distinguishedNames = new HashSet<String>();
private Group(String gid)
{
this.gid = "GROUP_" + gid;
}
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (!(o instanceof Group))
{
return false;
}
Group g = (Group) o;
return this.gid.equals(g.gid);
}
@Override
public int hashCode()
{
return gid.hashCode();
}
}
private static class SecondaryLink
{
String from;
String to;
private SecondaryLink(String from, String to)
{
this.from = from;
this.to = to;
}
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (!(o instanceof Group))
{
return false;
}
SecondaryLink l = (SecondaryLink) o;
return EqualsHelper.nullSafeEquals(this.from, l.from) && EqualsHelper.nullSafeEquals(this.to, l.to);
}
@Override
public int hashCode()
{
int hashCode = 0;
if (from != null)
{
hashCode = hashCode * 37 + from.hashCode();
}
if (to != null)
{
hashCode = hashCode * 37 + to.hashCode();
}
return hashCode;
}
}
public static void main(String[] args) throws IOException
{
ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
ExportSource source = (ExportSource) ctx.getBean("ldapGroupExportSource");
File file = new File(args[0]);
Writer writer = new BufferedWriter(new FileWriter(file));
XMLWriter xmlWriter = createXMLExporter(writer);
source.generateExport(xmlWriter);
xmlWriter.close();
}
private static XMLWriter createXMLExporter(Writer writer)
{
// Define output format
OutputFormat format = OutputFormat.createPrettyPrint();
format.setNewLineAfterDeclaration(false);
format.setIndentSize(3);
format.setEncoding("UTF-8");
// Construct an XML Exporter
XMLWriter xmlWriter = new XMLWriter(writer, format);
return xmlWriter;
}
public void afterPropertiesSet() throws Exception
{
viewRef = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "reference", namespaceService);
viewId = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "id", namespaceService);
viewIdRef = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "idref", namespaceService);
viewAssociations = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "associations", namespaceService);
childQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "childName", namespaceService);
viewValueQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "value", namespaceService);
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ldap;
import java.util.Map;
import javax.naming.directory.InitialDirContext;
import org.alfresco.repo.security.authentication.AuthenticationException;
/**
* Interface that defines a factory for obtaining ldap directory contexts.
*
* @author Andy Hind
*/
public interface LDAPInitialDirContextFactory
{
/**
* Set the LDAP environment Hashtable properties used ot initialise the LDAP connection.
*
* @param environment
*/
public void setInitialDirContextEnvironment(Map<String, String> environment);
/**
* Use the environment properties and connect to the LDAP server.
* Used to obtain read only access to the LDAP server.
*
* @return
* @throws AuthenticationException
*/
public InitialDirContext getDefaultIntialDirContext() throws AuthenticationException;
/**
* Augment the connection environment with the identity and credentials and bind to the ldap server.
* Mainly used to validate a user's credentials during authentication.
*
* @param principal
* @param credentials
* @return
* @throws AuthenticationException
*/
public InitialDirContext getInitialDirContext(String principal, String credentials) throws AuthenticationException;
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ldap;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.InitialDirContext;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ApplicationContext;
public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFactory
{
private Map<String, String> initialDirContextEnvironment = Collections.<String, String> emptyMap();
static
{
System.setProperty("javax.security.auth.useSubjectCredentialsOnly", "false");
}
public LDAPInitialDirContextFactoryImpl()
{
super();
}
public void setInitialDirContextEnvironment(Map<String, String> initialDirContextEnvironment)
{
this.initialDirContextEnvironment = initialDirContextEnvironment;
}
public Map<String, String> getInitialDirContextEnvironment()
{
return initialDirContextEnvironment;
}
public InitialDirContext getDefaultIntialDirContext() throws AuthenticationException
{
Hashtable<String, String> env = new Hashtable<String, String>(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
env.put("javax.security.auth.useSubjectCredsOnly", "false");
return buildInitialDirContext(env);
}
private InitialDirContext buildInitialDirContext(Hashtable<String, String> env) throws AuthenticationException
{
try
{
return new InitialDirContext(env);
}
catch (javax.naming.AuthenticationException ax)
{
throw new AuthenticationException("LDAP authentication failed.", ax);
}
catch (NamingException nx)
{
throw new AuthenticationException("Unable to connect to LDAP Server; check LDAP configuration", nx);
}
}
public InitialDirContext getInitialDirContext(String principal, String credentials) throws AuthenticationException
{
if (principal == null)
{
throw new AuthenticationException("Null user name provided.");
}
if (credentials == null)
{
throw new AuthenticationException("No credentials provided.");
}
Hashtable<String, String> env = new Hashtable<String, String>(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
env.put(Context.SECURITY_PRINCIPAL, principal);
env.put(Context.SECURITY_CREDENTIALS, credentials);
return buildInitialDirContext(env);
}
public static void main(String[] args)
{
// ....build a pyramid selling scheme .....
// A group has three user members and 2 group members .... and off we go ....
// We make the people and groups to represent this and stick them into LDAP ...used to populate a test data base for user and groups
int userMembers = Integer.parseInt(args[3]);
ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext();
LDAPInitialDirContextFactory factory = (LDAPInitialDirContextFactory) applicationContext
.getBean("ldapInitialDirContextFactory");
InitialDirContext ctx = null;
try
{
ctx = factory.getInitialDirContext("cn=" + args[0] + "," + args[2], args[1]);
/* Values we'll use in creating the entry */
Attribute objClasses = new BasicAttribute("objectclass");
objClasses.add("top");
objClasses.add("person");
objClasses.add("organizationalPerson");
objClasses.add("inetOrgPerson");
for (int i = 0; i < userMembers; i++)
{
Attribute cn = new BasicAttribute("cn", "User" + i + " TestUser");
Attribute sn = new BasicAttribute("sn", "TestUser");
Attribute givenNames = new BasicAttribute("givenName", "User" + i);
Attribute telephoneNumber = new BasicAttribute("telephoneNumber", "123");
Attribute uid = new BasicAttribute("uid", "User" + i);
Attribute mail = new BasicAttribute("mail", "woof@woof");
Attribute o = new BasicAttribute("o", "Alfresco");
Attribute userPassword = new BasicAttribute("userPassword", "bobbins");
/* Specify the DN we're adding */
String dn = "cn=User" + i + " TestUser," + args[2];
Attributes orig = new BasicAttributes();
orig.put(objClasses);
orig.put(cn);
orig.put(sn);
orig.put(givenNames);
orig.put(telephoneNumber);
orig.put(uid);
orig.put(mail);
orig.put(o);
orig.put(userPassword);
try
{
ctx.destroySubcontext(dn);
}
catch (NamingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
ctx.createSubcontext(dn, orig);
}
}
catch (NamingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
if (ctx != null)
{
try
{
ctx.close();
}
catch (NamingException e)
{
e.printStackTrace();
}
}
}
}
}

View File

@@ -0,0 +1,328 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ldap;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.Map;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.importer.ExportSource;
import org.alfresco.repo.importer.ExportSourceImporterException;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ApplicationContextHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.context.ApplicationContext;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
public class LDAPPersonExportSource implements ExportSource
{
private static Log s_logger = LogFactory.getLog(LDAPPersonExportSource.class);
private String personQuery = "(objectclass=inetOrgPerson)";
private String searchBase;
private String userIdAttributeName;
private LDAPInitialDirContextFactory ldapInitialContextFactory;
private PersonService personService;
private Map<String, String> attributeMapping;
private NamespaceService namespaceService;
private String defaultHomeFolder;
public LDAPPersonExportSource()
{
super();
}
public void setPersonQuery(String personQuery)
{
this.personQuery = personQuery;
}
public void setSearchBase(String searchBase)
{
this.searchBase = searchBase;
}
public void setUserIdAttributeName(String userIdAttributeName)
{
this.userIdAttributeName = userIdAttributeName;
}
public void setLDAPInitialDirContextFactory(LDAPInitialDirContextFactory ldapInitialDirContextFactory)
{
this.ldapInitialContextFactory = ldapInitialDirContextFactory;
}
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
public void setDefaultHomeFolder(String defaultHomeFolder)
{
this.defaultHomeFolder = defaultHomeFolder;
}
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
public void setAttributeMapping(Map<String, String> attributeMapping)
{
this.attributeMapping = attributeMapping;
}
public void generateExport(XMLWriter writer)
{
QName nodeUUID = QName.createQName("sys:node-uuid", namespaceService);
Collection<String> prefixes = namespaceService.getPrefixes();
QName childQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "childName", namespaceService);
try
{
AttributesImpl attrs = new AttributesImpl();
attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, childQName.getLocalName(), childQName
.toPrefixString(), null, ContentModel.TYPE_PERSON.toPrefixString(namespaceService));
writer.startDocument();
for (String prefix : prefixes)
{
if (!prefix.equals("xml"))
{
String uri = namespaceService.getNamespaceURI(prefix);
writer.startPrefixMapping(prefix, uri);
}
}
writer.startElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view",
NamespaceService.REPOSITORY_VIEW_PREFIX + ":" + "view", new AttributesImpl());
InitialDirContext ctx = null;
try
{
ctx = ldapInitialContextFactory.getDefaultIntialDirContext();
// Authentication has been successful.
// Set the current user, they are now authenticated.
SearchControls userSearchCtls = new SearchControls();
userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
System.out.println("COUNT "+userSearchCtls.getCountLimit());
System.out.println("TIME "+userSearchCtls.getTimeLimit());
userSearchCtls.setCountLimit(Integer.MAX_VALUE);
NamingEnumeration searchResults = ctx.search(searchBase, personQuery, userSearchCtls);
while (searchResults.hasMoreElements())
{
SearchResult result = (SearchResult) searchResults.next();
Attributes attributes = result.getAttributes();
Attribute uidAttribute = attributes.get(userIdAttributeName);
String uid = (String) uidAttribute.get(0);
if(s_logger.isDebugEnabled())
{
s_logger.debug("Adding user for "+uid);
}
System.out.println("User "+uid);
writer.startElement(ContentModel.TYPE_PERSON.getNamespaceURI(), ContentModel.TYPE_PERSON
.getLocalName(), ContentModel.TYPE_PERSON.toPrefixString(namespaceService), attrs);
// permissions
// owner
writer.startElement(ContentModel.ASPECT_OWNABLE.getNamespaceURI(), ContentModel.ASPECT_OWNABLE
.getLocalName(), ContentModel.ASPECT_OWNABLE.toPrefixString(namespaceService),
new AttributesImpl());
writer.endElement(ContentModel.ASPECT_OWNABLE.getNamespaceURI(), ContentModel.ASPECT_OWNABLE
.getLocalName(), ContentModel.ASPECT_OWNABLE.toPrefixString(namespaceService));
writer.startElement(ContentModel.PROP_OWNER.getNamespaceURI(), ContentModel.PROP_OWNER
.getLocalName(), ContentModel.PROP_OWNER.toPrefixString(namespaceService),
new AttributesImpl());
writer.characters(uid.toCharArray(), 0, uid.length());
writer.endElement(ContentModel.PROP_OWNER.getNamespaceURI(),
ContentModel.PROP_OWNER.getLocalName(), ContentModel.PROP_OWNER
.toPrefixString(namespaceService));
for (String key : attributeMapping.keySet())
{
QName keyQName = QName.createQName(key, namespaceService);
writer.startElement(keyQName.getNamespaceURI(), keyQName.getLocalName(), keyQName
.toPrefixString(namespaceService), new AttributesImpl());
// cater for null
String attribute = attributeMapping.get(key);
if (attribute != null)
{
String value = (String) attributes.get(attribute).get(0);
if (value != null)
{
writer.characters(value.toCharArray(), 0, value.length());
}
}
writer.endElement(keyQName.getNamespaceURI(), keyQName.getLocalName(), keyQName
.toPrefixString(namespaceService));
}
// Default home folder
if (!(attributeMapping.keySet().contains(ContentModel.PROP_HOMEFOLDER.toString()) || attributeMapping
.keySet().contains(ContentModel.PROP_HOMEFOLDER.toPrefixString(namespaceService))))
{
// Only if we are creating the person for the first time
if (!personService.personExists(uid))
{
writer.startElement(ContentModel.PROP_HOMEFOLDER.getNamespaceURI(),
ContentModel.PROP_HOMEFOLDER.getLocalName(), ContentModel.PROP_HOMEFOLDER
.toPrefixString(namespaceService), new AttributesImpl());
if (defaultHomeFolder != null)
{
writer.characters(defaultHomeFolder.toCharArray(), 0, defaultHomeFolder.length());
}
writer.endElement(ContentModel.PROP_HOMEFOLDER.getNamespaceURI(),
ContentModel.PROP_HOMEFOLDER.getLocalName(), ContentModel.PROP_HOMEFOLDER
.toPrefixString(namespaceService));
}
}
if (personService.personExists(uid))
{
String uguid = personService.getPerson(uid).getId();
writer.startElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID
.toPrefixString(namespaceService), new AttributesImpl());
writer.characters(uguid.toCharArray(), 0, uguid.length());
writer.endElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID
.toPrefixString(namespaceService));
}
writer.endElement(ContentModel.TYPE_PERSON.getNamespaceURI(), ContentModel.TYPE_PERSON
.getLocalName(), ContentModel.TYPE_PERSON.toPrefixString(namespaceService));
}
}
catch (NamingException e)
{
throw new ExportSourceImporterException("Failed to import people.", e);
}
finally
{
if (ctx != null)
{
try
{
ctx.close();
}
catch (NamingException e)
{
throw new ExportSourceImporterException("Failed to import people.", e);
}
}
}
for (String prefix : prefixes)
{
if (!prefix.equals("xml"))
{
writer.endPrefixMapping(prefix);
}
}
writer.endElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", NamespaceService.REPOSITORY_VIEW_PREFIX
+ ":" + "view");
writer.endDocument();
}
catch (SAXException e)
{
throw new ExportSourceImporterException("Failed to create file for import.", e);
}
}
public static void main(String[] args) throws IOException
{
ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
ExportSource source = (ExportSource) ctx.getBean("ldapPeopleExportSource");
File file = new File(args[0]);
Writer writer = new BufferedWriter(new FileWriter(file));
XMLWriter xmlWriter = createXMLExporter(writer);
source.generateExport(xmlWriter);
xmlWriter.close();
}
private static XMLWriter createXMLExporter(Writer writer)
{
// Define output format
OutputFormat format = OutputFormat.createPrettyPrint();
format.setNewLineAfterDeclaration(false);
format.setIndentSize(3);
format.setEncoding("UTF-8");
// Construct an XML Exporter
XMLWriter xmlWriter = new XMLWriter(writer, format);
return xmlWriter;
}
}

View File

@@ -0,0 +1,932 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ntlm;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.util.Enumeration;
import java.util.Hashtable;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationServiceException;
import net.sf.acegisecurity.BadCredentialsException;
import net.sf.acegisecurity.CredentialsExpiredException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.server.auth.PasswordEncryptor;
import org.alfresco.filesys.server.auth.passthru.AuthenticateSession;
import org.alfresco.filesys.server.auth.passthru.PassthruServers;
import org.alfresco.filesys.smb.SMBException;
import org.alfresco.filesys.smb.SMBStatus;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.NTLMMode;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PersonService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* NTLM Authentication Component Class
*
* <p>Provides authentication using passthru to a Windows server(s)/domain controller(s) using the accounts
* defined on the passthru server to validate users.
*
* @author GKSpencer
*/
public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationComponent
{
// Logging
private static final Log logger = LogFactory.getLog("org.alfresco.passthru.auth");
// Constants
//
// Standard authorities
public static final String NTLMAuthorityGuest = "Guest";
public static final String NTLMAuthorityAdministrator = "Administrator";
// Active session timeout
private static final long DefaultSessionTimeout = 60000L; // 1 minute
private static final long MinimumSessionTimeout = 5000L; // 5 seconds
// Passthru authentication servers
private PassthruServers m_passthruServers;
// Password encryptor for generating password hash for local authentication
private PasswordEncryptor m_encryptor;
// Allow guest access
private boolean m_allowGuest;
// Table of currently active passthru authentications and the associated authentication session
//
// If the two authentication stages are not completed within a reasonable time the authentication
// session will be closed by the reaper thread.
private Hashtable<NTLMPassthruToken,AuthenticateSession> m_passthruSessions;
// Active authentication session timeout, in milliseconds
private long m_passthruSessTmo = DefaultSessionTimeout;
// Authentication session reaper thread
private PassthruReaperThread m_reaperThread;
// Person service, used to map passthru usernames to Alfresco person names
private PersonService m_personService;
private NodeService m_nodeService;
/**
* Passthru Session Reaper Thread
*/
class PassthruReaperThread extends Thread
{
// Thread shutdown request flag
private boolean m_ishutdown;
// Reaper wakeup interval, in milliseconds
private long m_wakeupInterval = m_passthruSessTmo / 2;
/**
* Default constructor
*/
PassthruReaperThread()
{
setDaemon(true);
setName("PassthruReaper");
start();
}
/**
* Set the wakeup interval
*
* @param wakeup long
*/
public final void setWakeup(long wakeup)
{
m_wakeupInterval = wakeup;
}
/**
* Main thread code
*/
public void run()
{
// Loop until shutdown
m_ishutdown = false;
while ( m_ishutdown == false)
{
// Sleep for a while
try
{
sleep( m_wakeupInterval);
}
catch ( InterruptedException ex)
{
}
// Check if there are any active sessions to check
if ( m_passthruSessions.size() > 0)
{
// Enumerate the active sessions
Enumeration<NTLMPassthruToken> tokenEnum = m_passthruSessions.keys();
long timeNow = System.currentTimeMillis();
while (tokenEnum.hasMoreElements())
{
// Get the current NTLM token and check if it has expired
NTLMPassthruToken ntlmToken = tokenEnum.nextElement();
if ( ntlmToken != null && ntlmToken.getAuthenticationExpireTime() < timeNow)
{
// Authentication token has expired, close the associated authentication session
AuthenticateSession authSess = m_passthruSessions.get(ntlmToken);
if ( authSess != null)
{
try
{
// Close the authentication session
authSess.CloseSession();
}
catch ( Exception ex)
{
// Debug
if(logger.isDebugEnabled())
logger.debug("Error closing expired authentication session", ex);
}
}
// Remove the expired token from the active list
m_passthruSessions.remove(ntlmToken);
// Debug
if(logger.isDebugEnabled())
logger.debug("Removed expired NTLM token " + ntlmToken);
}
}
}
}
// Debug
if(logger.isDebugEnabled())
logger.debug("Passthru reaper thread shutdown");
}
/**
* Shutdown the reaper thread
*/
public final void shutdownRequest()
{
m_ishutdown = true;
this.interrupt();
}
}
/**
* Class constructor
*/
public NTLMAuthenticationComponentImpl() {
// Create the passthru authentication server list
m_passthruServers = new PassthruServers();
// Create the password encryptor for local password hashing
m_encryptor = new PasswordEncryptor();
// Create the active session list and reaper thread
m_passthruSessions = new Hashtable<NTLMPassthruToken,AuthenticateSession>();
m_reaperThread = new PassthruReaperThread();
}
/**
* Determine if guest logons are allowed
*
* @return boolean
*/
public final boolean allowsGuest()
{
return m_allowGuest;
}
/**
* Set the domain to authenticate against
*
* @param domain String
*/
public void setDomain(String domain) {
// Check if the passthru server list is already configured
if ( m_passthruServers.getTotalServerCount() > 0)
throw new AlfrescoRuntimeException("Passthru server list already configured");
// Configure the passthru authentication server list using the domain controllers
m_passthruServers.setDomain(domain);
}
/**
* Set the server(s) to authenticate against
*
* @param servers String
*/
public void setServers(String servers) {
// Check if the passthru server list is already configured
if ( m_passthruServers.getTotalServerCount() > 0)
throw new AlfrescoRuntimeException("Passthru server list already configured");
// Configure the passthru authenticaiton list using a list of server names/addresses
m_passthruServers.setServerList(servers);
}
/**
* Use the local server as the authentication server
*
* @param useLocal String
*/
public void setUseLocalServer(String useLocal)
{
// Check if the local server should be used for authentication
if ( Boolean.parseBoolean(useLocal) == true)
{
// Check if the passthru server list is already configured
if ( m_passthruServers.getTotalServerCount() > 0)
throw new AlfrescoRuntimeException("Passthru server list already configured");
try
{
// Get the list of local network addresses
InetAddress[] localAddrs = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName());
// Build the list of local addresses
if ( localAddrs != null && localAddrs.length > 0)
{
StringBuilder addrStr = new StringBuilder();
for ( InetAddress curAddr : localAddrs)
{
if ( curAddr.isLoopbackAddress() == false)
{
addrStr.append(curAddr.getHostAddress());
addrStr.append(",");
}
}
if ( addrStr.length() > 0)
addrStr.setLength(addrStr.length() - 1);
// Set the server list using the local address list
m_passthruServers.setServerList(addrStr.toString());
}
else
throw new AlfrescoRuntimeException("No local server address(es)");
}
catch ( UnknownHostException ex)
{
throw new AlfrescoRuntimeException("Failed to get local address list");
}
}
}
/**
* Allow guest access
*
* @param guest String
*/
public void setGuestAccess(String guest)
{
m_allowGuest = Boolean.parseBoolean(guest);
}
/**
* Set the JCE provider
*
* @param providerClass String
*/
public void setJCEProvider(String providerClass)
{
// Set the JCE provider, required to provide various encryption/hashing algorithms not available
// in the standard Sun JDK/JRE
try
{
// Load the JCE provider class and validate
Object jceObj = Class.forName(providerClass).newInstance();
if (jceObj instanceof java.security.Provider)
{
// Inform listeners, validate the configuration change
Provider jceProvider = (Provider) jceObj;
// Add the JCE provider
Security.addProvider(jceProvider);
// Debug
if ( logger.isDebugEnabled())
logger.debug("Using JCE provider " + providerClass);
}
else
{
throw new AlfrescoRuntimeException("JCE provider class is not a valid Provider class");
}
}
catch (ClassNotFoundException ex)
{
throw new AlfrescoRuntimeException("JCE provider class " + providerClass + " not found");
}
catch (Exception ex)
{
throw new AlfrescoRuntimeException("JCE provider class error", ex);
}
}
/**
* Set the authentication session timeout, in seconds
*
* @param sessTmo String
*/
public void setSessionTimeout(String sessTmo)
{
// Convert to an integer value and range check the timeout value
try
{
// Convert to an integer value
long sessTmoMilli = Long.parseLong(sessTmo) * 1000L;
if ( sessTmoMilli < MinimumSessionTimeout)
throw new AlfrescoRuntimeException("Authentication session timeout too low, " + sessTmo);
// Set the authentication session timeout value
m_passthruSessTmo = sessTmoMilli;
// Set the reaper thread wakeup interval
m_reaperThread.setWakeup( sessTmoMilli / 2);
}
catch(NumberFormatException ex)
{
throw new AlfrescoRuntimeException("Invalid authenication session timeout value");
}
}
/**
* Set the person service
*
* @param personService PersonService
*/
public final void setPersonService(PersonService personService)
{
m_personService = personService;
}
/**
* Set the node service
*
* @param nodeService NodeService
*/
public final void setNodeService(NodeService nodeService)
{
m_nodeService = nodeService;
}
/**
* Return the authentication session timeout, in milliseconds
*
* @return long
*/
private final long getSessionTimeout()
{
return m_passthruSessTmo;
}
/**
* Authenticate
*
* @param userName String
* @param password char[]
* @throws AuthenticationException
*/
public void authenticate(String userName, char[] password) throws AuthenticationException
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Authenticate user=" + userName + " via local credentials");
// Create a local authentication token
NTLMLocalToken authToken = new NTLMLocalToken(userName, new String(password));
// Authenticate using the token
authenticate( authToken);
setCurrentUser( userName.toLowerCase());
}
/**
* Authenticate using a token
*
* @param token Authentication
* @return Authentication
* @throws AuthenticationException
*/
public Authentication authenticate(Authentication auth) throws AuthenticationException
{
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Authenticate " + auth + " via token");
// Check if the token is for passthru authentication
if( auth instanceof NTLMPassthruToken)
{
// Access the NTLM passthru token
NTLMPassthruToken ntlmToken = (NTLMPassthruToken) auth;
// Authenticate using passthru
authenticatePassthru(ntlmToken);
}
// Check for a local authentication token
else if( auth instanceof NTLMLocalToken)
{
AuthenticateSession authSess = null;
try
{
// Access the NTLM token
NTLMLocalToken ntlmToken = (NTLMLocalToken) auth;
// Open a session to an authentication server
authSess = m_passthruServers.openSession();
// Authenticate using the credentials supplied
authenticateLocal(ntlmToken, authSess);
}
finally
{
// Make sure the authentication session is closed
if ( authSess != null)
{
try
{
authSess.CloseSession();
}
catch ( Exception ex)
{
}
}
}
}
else
{
// Unsupported authentication token
throw new AuthenticationException("Unsupported authentication token type");
}
// Return the updated authentication token
return getCurrentAuthentication();
}
/**
* Get the enum that describes NTLM integration
*
* @return NTLMMode
*/
public NTLMMode getNTLMMode()
{
return NTLMMode.PASS_THROUGH;
}
/**
* Get the MD4 password hash, as required by NTLM based authentication methods.
*
* @param userName String
* @return String
*/
public String getMD4HashedPassword(String userName)
{
// Do not support MD4 hashed password
throw new AlfrescoRuntimeException("MD4 passwords not supported");
}
/**
* Authenticate a user using local credentials
*
* @param ntlmToken NTLMLocalToken
* @param authSess AuthenticateSession
*/
private void authenticateLocal(NTLMLocalToken ntlmToken, AuthenticateSession authSess)
{
try
{
// Get the plaintext password and generate an NTLM1 password hash
String username = (String) ntlmToken.getPrincipal();
String plainPwd = (String) ntlmToken.getCredentials();
byte[] ntlm1Pwd = m_encryptor.generateEncryptedPassword( plainPwd, authSess.getEncryptionKey(), PasswordEncryptor.NTLM1);
// Send the logon request to the authentication server
//
// Note: Only use the stronger NTLM hash, we do not send the LM hash
authSess.doSessionSetup(username, null, ntlm1Pwd);
// Check if the session has logged on as a guest
if ( authSess.isGuest() || username.equalsIgnoreCase("GUEST"))
{
// If guest access is enabled add a guest authority to the token
if ( allowsGuest())
{
// Set the guest authority
GrantedAuthority[] authorities = new GrantedAuthority[2];
authorities[0] = new GrantedAuthorityImpl(NTLMAuthorityGuest);
authorities[1] = new GrantedAuthorityImpl("ROLE_AUTHENTICATED");
ntlmToken.setAuthorities(authorities);
}
else
{
// Guest access not allowed
throw new AuthenticationException("Guest logons disabled");
}
}
else
{
// Set authorities
GrantedAuthority[] authorities = new GrantedAuthority[1];
authorities[0] = new GrantedAuthorityImpl("ROLE_AUTHENTICATED");
ntlmToken.setAuthorities(authorities);
}
// Indicate that the token is authenticated
ntlmToken.setAuthenticated(true);
// Map the passthru username to an Alfresco person
NodeRef userNode = m_personService.getPerson(username);
if ( userNode != null)
{
// Get the person name and use that as the current user to line up with permission checks
String personName = (String) m_nodeService.getProperty(userNode, ContentModel.PROP_USERNAME);
setCurrentUser(personName);
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Setting current user using person " + personName + " (username " + username + ")");
}
else
{
// Set using the user name, lowercase the name if hte person service is case insensitive
if ( m_personService.getUserNamesAreCaseSensitive() == false)
username = username.toLowerCase();
setCurrentUser( username);
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Setting current user using username " + username);
}
// Debug
if ( logger.isDebugEnabled())
logger.debug("Authenticated token=" + ntlmToken);
}
catch (NoSuchAlgorithmException ex)
{
// JCE provider does not have the required encryption/hashing algorithms
throw new AuthenticationServiceException("JCE provider error", ex);
}
catch (IOException ex)
{
// Error connecting to the authentication server
throw new AuthenticationServiceException("I/O error", ex);
}
catch (SMBException ex)
{
// Check the returned status code to determine why the logon failed and throw an appropriate exception
if ( ex.getErrorClass() == SMBStatus.NTErr)
{
AuthenticationException authEx = null;
switch( ex.getErrorCode())
{
case SMBStatus.NTLogonFailure:
authEx = new AuthenticationException("Logon failure");
break;
case SMBStatus.NTAccountDisabled:
authEx = new AuthenticationException("Account disabled");
break;
default:
authEx = new AuthenticationException("Logon failure");
break;
}
throw authEx;
}
else
throw new AuthenticationException("Logon failure");
}
}
/**
* Authenticate using passthru authentication with a client
*
* @param ntlmToken NTLMPassthruToken
*/
private void authenticatePassthru(NTLMPassthruToken ntlmToken)
{
// Check if the token has an authentication session, if not then it is either a new token
// or the session has been timed out
AuthenticateSession authSess = m_passthruSessions.get(ntlmToken);
if ( authSess == null)
{
// Check if the token has a challenge, if it does then the associated session has been
// timed out
if ( ntlmToken.getChallenge() != null)
throw new CredentialsExpiredException("Authentication session expired");
// Open an authentication session for the new token and add to the active session list
authSess = m_passthruServers.openSession();
ntlmToken.setAuthenticationExpireTime(System.currentTimeMillis() + getSessionTimeout());
// Get the challenge from the initial session negotiate stage
ntlmToken.setChallenge(new NTLMChallenge(authSess.getEncryptionKey()));
StringBuilder details = new StringBuilder();
// Build a details string with the authentication session details
details.append(authSess.getDomain());
details.append("\\");
details.append(authSess.getPCShare().getNodeName());
details.append(",");
details.append(authSess.getSession().getProtocolName());
ntlmToken.setDetails(details.toString());
// Put the token/session into the active session list
m_passthruSessions.put(ntlmToken, authSess);
// Debug
if ( logger.isDebugEnabled())
logger.debug("Passthru stage 1 token " + ntlmToken);
}
else
{
try
{
// Stage two of the authentication, send the hashed password to the authentication server
byte[] lmPwd = null;
byte[] ntlmPwd = null;
if ( ntlmToken.getPasswordType() == PasswordEncryptor.LANMAN)
lmPwd = ntlmToken.getHashedPassword();
else if ( ntlmToken.getPasswordType() == PasswordEncryptor.NTLM1)
ntlmPwd = ntlmToken.getHashedPassword();
String username = (String) ntlmToken.getPrincipal();
authSess.doSessionSetup(username, lmPwd, ntlmPwd);
// Check if the session has logged on as a guest
if ( authSess.isGuest() || username.equalsIgnoreCase("GUEST"))
{
// If guest access is enabled add a guest authority to the token
if ( allowsGuest())
{
// Set the guest authority
GrantedAuthority[] authorities = new GrantedAuthority[1];
authorities[0] = new GrantedAuthorityImpl(NTLMAuthorityGuest);
ntlmToken.setAuthorities(authorities);
}
else
{
// Guest access not allowed
throw new BadCredentialsException("Guest logons disabled");
}
}
// Indicate that the token is authenticated
ntlmToken.setAuthenticated(true);
// Map the passthru username to an Alfresco person
NodeRef userNode = m_personService.getPerson(username);
if ( userNode != null)
{
// Get the person name and use that as the current user to line up with permission checks
String personName = (String) m_nodeService.getProperty(userNode, ContentModel.PROP_USERNAME);
setCurrentUser(personName);
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Setting current user using person " + personName + " (username " + username + ")");
}
else
{
// Set using the user name, lowercase the name if the person service is case insensitive
if ( m_personService.getUserNamesAreCaseSensitive() == false)
username = username.toLowerCase();
setCurrentUser( username);
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Setting current user using username " + username);
}
}
catch (IOException ex)
{
// Error connecting to the authentication server
throw new AuthenticationServiceException("I/O error", ex);
}
catch (SMBException ex)
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Passthru exception, " + ex);
// Check the returned status code to determine why the logon failed and throw an appropriate exception
if ( ex.getErrorClass() == SMBStatus.NTErr)
{
AuthenticationException authEx = null;
switch( ex.getErrorCode())
{
case SMBStatus.NTLogonFailure:
authEx = new AuthenticationException("Logon failure");
break;
case SMBStatus.NTAccountDisabled:
authEx = new AuthenticationException("Account disabled");
break;
default:
authEx = new AuthenticationException("Logon failure");
break;
}
throw authEx;
}
else
throw new BadCredentialsException("Logon failure");
}
finally
{
// Make sure the authentication session is closed
if ( authSess != null)
{
try
{
// Remove the session from the active list
m_passthruSessions.remove(ntlmToken);
// Close the session to the authentication server
authSess.CloseSession();
}
catch (Exception ex)
{
}
}
}
}
}
/**
* Check if the user exists
*
* @param userName String
* @return boolean
*/
public boolean exists(String userName)
{
throw new UnsupportedOperationException();
}
@Override
protected boolean implementationAllowsGuestLogin()
{
return allowsGuest();
}
}

View File

@@ -0,0 +1,755 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ntlm;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.util.Enumeration;
import java.util.Hashtable;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.server.auth.PasswordEncryptor;
import org.alfresco.filesys.server.auth.passthru.AuthenticateSession;
import org.alfresco.filesys.server.auth.passthru.PassthruServers;
import org.alfresco.filesys.smb.SMBException;
import org.alfresco.filesys.smb.SMBStatus;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.acegisecurity.*;
import net.sf.acegisecurity.providers.*;
/**
* NTLM Authentication Provider
*
* @author GKSpencer
*/
public class NTLMAuthenticationProvider implements AuthenticationProvider
{
private static final Log logger = LogFactory.getLog("org.alfresco.acegi");
// Constants
//
// Standard authorities
public static final String NTLMAuthorityGuest = "Guest";
public static final String NTLMAuthorityAdministrator = "Administrator";
// Active session timeout
private static final long DefaultSessionTimeout = 60000L; // 1 minute
private static final long MinimumSessionTimeout = 5000L; // 5 seconds
// Passthru authentication servers
private PassthruServers m_passthruServers;
// Password encryptor for generating password hash for local authentication
private PasswordEncryptor m_encryptor;
// Allow guest access
private boolean m_allowGuest;
// Table of currently active passthru authentications and the associated authentication session
//
// If the two authentication stages are not completed within a reasonable time the authentication
// session will be closed by the reaper thread.
private Hashtable<NTLMPassthruToken,AuthenticateSession> m_passthruSessions;
// Active authentication session timeout, in milliseconds
private long m_passthruSessTmo = DefaultSessionTimeout;
// Authentication session reaper thread
private PassthruReaperThread m_reaperThread;
/**
* Passthru Session Repear Thread
*/
class PassthruReaperThread extends Thread
{
// Thread shutdown request flag
private boolean m_ishutdown;
// Reaper wakeup interval, in milliseconds
private long m_wakeupInterval = m_passthruSessTmo / 2;
/**
* Default constructor
*/
PassthruReaperThread()
{
setDaemon(true);
setName("PassthruReaper");
start();
}
/**
* Set the wakeup interval
*
* @param wakeup long
*/
public final void setWakeup(long wakeup)
{
m_wakeupInterval = wakeup;
}
/**
* Main thread code
*/
public void run()
{
// Loop until shutdown
m_ishutdown = false;
while ( m_ishutdown == false)
{
// Sleep for a while
try
{
sleep( m_wakeupInterval);
}
catch ( InterruptedException ex)
{
}
// Check if there are any active sessions to check
if ( m_passthruSessions.size() > 0)
{
// Enumerate the active sessions
Enumeration<NTLMPassthruToken> tokenEnum = m_passthruSessions.keys();
long timeNow = System.currentTimeMillis();
while (tokenEnum.hasMoreElements())
{
// Get the current NTLM token and check if it has expired
NTLMPassthruToken ntlmToken = tokenEnum.nextElement();
if ( ntlmToken != null && ntlmToken.getAuthenticationExpireTime() < timeNow)
{
// Authentication token has expired, close the associated authentication session
AuthenticateSession authSess = m_passthruSessions.get(ntlmToken);
if ( authSess != null)
{
try
{
// Close the authentication session
authSess.CloseSession();
}
catch ( Exception ex)
{
// Debug
if(logger.isDebugEnabled())
logger.debug("Error closing expired authentication session", ex);
}
}
// Remove the expired token from the active list
m_passthruSessions.remove(ntlmToken);
// Debug
if(logger.isDebugEnabled())
logger.debug("Removed expired NTLM token " + ntlmToken);
}
}
}
}
// Debug
if(logger.isDebugEnabled())
logger.debug("Passthru reaper thread shutdown");
}
/**
* Shutdown the reaper thread
*/
public final void shutdownRequest()
{
m_ishutdown = true;
this.interrupt();
}
}
/**
* Class constructor
*/
public NTLMAuthenticationProvider() {
// Create the passthru authentication server list
m_passthruServers = new PassthruServers();
// Create the password encryptor for local password hashing
m_encryptor = new PasswordEncryptor();
// Create the active session list and reaper thread
m_passthruSessions = new Hashtable<NTLMPassthruToken,AuthenticateSession>();
m_reaperThread = new PassthruReaperThread();
}
/**
* Authenticate a user
*
* @param auth Authentication
* @return Authentication
* @exception AuthenticationException
*/
public Authentication authenticate(Authentication auth) throws AuthenticationException
{
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Authenticate " + auth);
// Check if the token is for passthru authentication
if( auth instanceof NTLMPassthruToken)
{
// Access the NTLM passthru token
NTLMPassthruToken ntlmToken = (NTLMPassthruToken) auth;
// Authenticate using passthru
authenticatePassthru(ntlmToken);
}
// Check for a local authentication token
else if( auth instanceof NTLMLocalToken)
{
AuthenticateSession authSess = null;
try
{
// Access the NTLM token
NTLMLocalToken ntlmToken = (NTLMLocalToken) auth;
// Open a session to an authentication server
authSess = m_passthruServers.openSession();
// Authenticate using the credentials supplied
authenticateLocal(ntlmToken, authSess);
}
finally
{
// Make sure the authentication session is closed
if ( authSess != null)
{
try
{
authSess.CloseSession();
}
catch ( Exception ex)
{
}
}
}
}
// Return the updated authentication token
return auth;
}
/**
* Determine if this provider supports the specified authentication token
*
* @param authentication Class
*/
public boolean supports(Class authentication)
{
// Check if the authentication is an NTLM authentication token
if ( NTLMPassthruToken.class.isAssignableFrom(authentication))
return true;
return NTLMLocalToken.class.isAssignableFrom(authentication);
}
/**
* Determine if guest logons are allowed
*
* @return boolean
*/
public final boolean allowsGuest()
{
return m_allowGuest;
}
/**
* Set the domain to authenticate against
*
* @param domain String
*/
public final void setDomain(String domain) {
// Check if the passthru server list is already configured
if ( m_passthruServers.getTotalServerCount() > 0)
throw new AlfrescoRuntimeException("Passthru server list already configured");
// Configure the passthru authentication server list using the domain controllers
m_passthruServers.setDomain(domain);
}
/**
* Set the server(s) to authenticate against
*
* @param servers String
*/
public final void setServers(String servers) {
// Check if the passthru server list is already configured
if ( m_passthruServers.getTotalServerCount() > 0)
throw new AlfrescoRuntimeException("Passthru server list already configured");
// Configure the passthru authenticaiton list using a list of server names/addresses
m_passthruServers.setServerList(servers);
}
/**
* Use the local server as the authentication server
*
* @param useLocal String
*/
public final void setUseLocalServer(String useLocal)
{
// Check if the local server should be used for authentication
if ( Boolean.parseBoolean(useLocal) == true)
{
// Check if the passthru server list is already configured
if ( m_passthruServers.getTotalServerCount() > 0)
throw new AlfrescoRuntimeException("Passthru server list already configured");
try
{
// Get the list of local network addresses
InetAddress[] localAddrs = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName());
// Build the list of local addresses
if ( localAddrs != null && localAddrs.length > 0)
{
StringBuilder addrStr = new StringBuilder();
for ( InetAddress curAddr : localAddrs)
{
if ( curAddr.isLoopbackAddress() == false)
{
addrStr.append(curAddr.getHostAddress());
addrStr.append(",");
}
}
if ( addrStr.length() > 0)
addrStr.setLength(addrStr.length() - 1);
// Set the server list using the local address list
m_passthruServers.setServerList(addrStr.toString());
}
else
throw new AlfrescoRuntimeException("No local server address(es)");
}
catch ( UnknownHostException ex)
{
throw new AlfrescoRuntimeException("Failed to get local address list");
}
}
}
/**
* Allow guest access
*
* @param guest String
*/
public final void setGuestAccess(String guest)
{
m_allowGuest = Boolean.parseBoolean(guest);
}
/**
* Set the JCE provider
*
* @param providerClass String
*/
public final void setJCEProvider(String providerClass)
{
// Set the JCE provider, required to provide various encryption/hashing algorithms not available
// in the standard Sun JDK/JRE
try
{
// Load the JCE provider class and validate
Object jceObj = Class.forName(providerClass).newInstance();
if (jceObj instanceof java.security.Provider)
{
// Inform listeners, validate the configuration change
Provider jceProvider = (Provider) jceObj;
// Add the JCE provider
Security.addProvider(jceProvider);
// Debug
if ( logger.isDebugEnabled())
logger.debug("Using JCE provider " + providerClass);
}
else
{
throw new AlfrescoRuntimeException("JCE provider class is not a valid Provider class");
}
}
catch (ClassNotFoundException ex)
{
throw new AlfrescoRuntimeException("JCE provider class " + providerClass + " not found");
}
catch (Exception ex)
{
throw new AlfrescoRuntimeException("JCE provider class error", ex);
}
}
/**
* Set the authentication session timeout, in seconds
*
* @param sessTmo String
*/
public final void setSessionTimeout(String sessTmo)
{
// Convert to an integer value and range check the timeout value
try
{
// Convert to an integer value
long sessTmoMilli = Long.parseLong(sessTmo) * 1000L;
if ( sessTmoMilli < MinimumSessionTimeout)
throw new AlfrescoRuntimeException("Authentication session timeout too low, " + sessTmo);
// Set the authentication session timeout value
m_passthruSessTmo = sessTmoMilli;
// Set the reaper thread wakeup interval
m_reaperThread.setWakeup( sessTmoMilli / 2);
}
catch(NumberFormatException ex)
{
throw new AlfrescoRuntimeException("Invalid authenication session timeout value");
}
}
/**
* Return the authentication session timeout, in milliseconds
*
* @return long
*/
private final long getSessionTimeout()
{
return m_passthruSessTmo;
}
/**
* Authenticate a user using local credentials
*
* @param ntlmToken NTLMLocalToken
* @param authSess AuthenticateSession
*/
private void authenticateLocal(NTLMLocalToken ntlmToken, AuthenticateSession authSess)
{
try
{
// Get the plaintext password and generate an NTLM1 password hash
String username = (String) ntlmToken.getPrincipal();
String plainPwd = (String) ntlmToken.getCredentials();
byte[] ntlm1Pwd = m_encryptor.generateEncryptedPassword( plainPwd, authSess.getEncryptionKey(), PasswordEncryptor.NTLM1);
// Send the logon request to the authentication server
//
// Note: Only use the stronger NTLM hash, we do not send the LM hash
authSess.doSessionSetup(username, null, ntlm1Pwd);
// Check if the session has logged on as a guest
if ( authSess.isGuest() || username.equalsIgnoreCase("GUEST"))
{
// If guest access is enabled add a guest authority to the token
if ( allowsGuest())
{
// Set the guest authority
GrantedAuthority[] authorities = new GrantedAuthority[1];
authorities[0] = new GrantedAuthorityImpl(NTLMAuthorityGuest);
ntlmToken.setAuthorities(authorities);
}
else
{
// Guest access not allowed
throw new BadCredentialsException("Guest logons disabled");
}
}
// Indicate that the token is authenticated
ntlmToken.setAuthenticated(true);
}
catch (NoSuchAlgorithmException ex)
{
// JCE provider does not have the required encryption/hashing algorithms
throw new AuthenticationServiceException("JCE provider error", ex);
}
catch (IOException ex)
{
// Error connecting to the authentication server
throw new AuthenticationServiceException("I/O error", ex);
}
catch (SMBException ex)
{
// Check the returned status code to determine why the logon failed and throw an appropriate exception
if ( ex.getErrorClass() == SMBStatus.NTErr)
{
AuthenticationException authEx = null;
switch( ex.getErrorCode())
{
case SMBStatus.NTLogonFailure:
authEx = new BadCredentialsException("Logon failure");
break;
case SMBStatus.NTAccountDisabled:
authEx = new DisabledException("Account disabled");
break;
default:
authEx = new BadCredentialsException("Logon failure");
break;
}
throw authEx;
}
else
throw new BadCredentialsException("Logon failure");
}
}
/**
* Authenticate using passthru authentication with a client
*
* @param ntlmToken NTLMPassthruToken
*/
private void authenticatePassthru(NTLMPassthruToken ntlmToken)
{
// Check if the token has an authentication session, if not then it is either a new token
// or the session has been timed out
AuthenticateSession authSess = m_passthruSessions.get(ntlmToken);
if ( authSess == null)
{
// Check if the token has a challenge, if it does then the associated session has been
// timed out
if ( ntlmToken.getChallenge() != null)
throw new CredentialsExpiredException("Authentication session expired");
// Open an authentication session for the new token and add to the active session list
authSess = m_passthruServers.openSession();
ntlmToken.setAuthenticationExpireTime(System.currentTimeMillis() + getSessionTimeout());
// Get the challenge from the initial session negotiate stage
ntlmToken.setChallenge(new NTLMChallenge(authSess.getEncryptionKey()));
StringBuilder details = new StringBuilder();
// Build a details string with the authentication session details
details.append(authSess.getDomain());
details.append("\\");
details.append(authSess.getPCShare().getNodeName());
details.append(",");
details.append(authSess.getSession().getProtocolName());
ntlmToken.setDetails(details.toString());
// Put the token/session into the active session list
m_passthruSessions.put(ntlmToken, authSess);
// Debug
if ( logger.isDebugEnabled())
logger.debug("Passthru stage 1 token " + ntlmToken);
}
else
{
try
{
// Stage two of the authentication, send the hashed password to the authentication server
byte[] lmPwd = null;
byte[] ntlmPwd = null;
if ( ntlmToken.getPasswordType() == PasswordEncryptor.LANMAN)
lmPwd = ntlmToken.getHashedPassword();
else if ( ntlmToken.getPasswordType() == PasswordEncryptor.NTLM1)
ntlmPwd = ntlmToken.getHashedPassword();
String username = (String) ntlmToken.getPrincipal();
authSess.doSessionSetup(username, lmPwd, ntlmPwd);
// Check if the session has logged on as a guest
if ( authSess.isGuest() || username.equalsIgnoreCase("GUEST"))
{
// If guest access is enabled add a guest authority to the token
if ( allowsGuest())
{
// Set the guest authority
GrantedAuthority[] authorities = new GrantedAuthority[1];
authorities[0] = new GrantedAuthorityImpl(NTLMAuthorityGuest);
ntlmToken.setAuthorities(authorities);
}
else
{
// Guest access not allowed
throw new BadCredentialsException("Guest logons disabled");
}
}
// Indicate that the token is authenticated
ntlmToken.setAuthenticated(true);
}
catch (IOException ex)
{
// Error connecting to the authentication server
throw new AuthenticationServiceException("I/O error", ex);
}
catch (SMBException ex)
{
// Check the returned status code to determine why the logon failed and throw an appropriate exception
if ( ex.getErrorClass() == SMBStatus.NTErr)
{
AuthenticationException authEx = null;
switch( ex.getErrorCode())
{
case SMBStatus.NTLogonFailure:
authEx = new BadCredentialsException("Logon failure");
break;
case SMBStatus.NTAccountDisabled:
authEx = new DisabledException("Account disabled");
break;
default:
authEx = new BadCredentialsException("Logon failure");
break;
}
throw authEx;
}
else
throw new BadCredentialsException("Logon failure");
}
finally
{
// Make sure the authentication session is closed
if ( authSess != null)
{
try
{
// Remove the session from the active list
m_passthruSessions.remove(ntlmToken);
// Close the session to the authentication server
authSess.CloseSession();
}
catch (Exception ex)
{
}
}
}
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ntlm;
import org.alfresco.filesys.util.HexDump;
/**
* Contains the NTLM challenge bytes.
*
* @author GKSpencer
*/
public class NTLMChallenge
{
// Challenge bytes
private byte[] m_challenge;
/**
* Class constructor
*
* @param chbyts byte[]
*/
protected NTLMChallenge(byte[] chbyts)
{
m_challenge = chbyts;
}
/**
* Return the challenge bytes
*
* @return byte[]
*/
public final byte[] getBytes()
{
return m_challenge;
}
/**
* Check for object equality
*
* @param obj Object
* @return boolean
*/
public boolean equals(Object obj)
{
if ( obj instanceof NTLMChallenge)
{
NTLMChallenge ntlmCh = (NTLMChallenge) obj;
// Check if both challenges are null
if ( getBytes() == null && ntlmCh.getBytes() == null)
return true;
// Check if both challenges are the same length
if ( getBytes() != null && ntlmCh.getBytes() != null &&
getBytes().length == ntlmCh.getBytes().length)
{
// Check if challenages are the same value
byte[] ntlmBytes = ntlmCh.getBytes();
for ( int i = 0; i < m_challenge.length; i++)
if ( m_challenge[i] != ntlmBytes[i])
return false;
}
else
return false;
}
// Not the same type
return false;
}
/**
* Return the challenge as a string
*
* @return String
*/
public String toString()
{
StringBuilder str = new StringBuilder();
str.append("[");
str.append(HexDump.hexString(getBytes(), " "));
str.append("]");
return str.toString();
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ntlm;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.providers.*;
/**
* <p>Used to provide authentication with a remote Windows server when the username and password are
* provided locally.
*
* @author GKSpencer
*/
public class NTLMLocalToken extends UsernamePasswordAuthenticationToken
{
private static final long serialVersionUID = -7946514578455279387L;
/**
* Class constructor
*/
protected NTLMLocalToken()
{
super(null, null);
}
/**
* Class constructor
*
* @param username String
* @param plainPwd String
*/
public NTLMLocalToken(String username, String plainPwd) {
super(username.toLowerCase(), plainPwd);
}
/**
* Check if the user logged on as a guest
*
* @return boolean
*/
public final boolean isGuestLogon()
{
return hasAuthority(NTLMAuthenticationProvider.NTLMAuthorityGuest);
}
/**
* Check if the user is an administrator
*
* @return boolean
*/
public final boolean isAdministrator()
{
return hasAuthority(NTLMAuthenticationProvider.NTLMAuthorityAdministrator);
}
/**
* Search for the specified authority
*
* @param authority String
* @return boolean
*/
public final boolean hasAuthority(String authority)
{
boolean found = false;
GrantedAuthority[] authorities = getAuthorities();
if ( authorities != null && authorities.length > 0)
{
// Search for the specified authority
int i = 0;
while ( found == false && i < authorities.length)
{
if ( authorities[i++].getAuthority().equals(authority))
found = true;
}
}
// Return the status
return found;
}
}

View File

@@ -0,0 +1,158 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ntlm;
/**
* <p>Used to provide passthru authentication to a remote Windows server using multiple stages that
* allows authentication details to be passed between a client and the remote authenticating server without
* the password being known by the authentication provider.
*
* @author GKSpencer
*/
public class NTLMPassthruToken extends NTLMLocalToken
{
private static final long serialVersionUID = -4635444888514735368L;
// Challenge for this session
private NTLMChallenge m_challenge;
// User name, hashed password and algorithm type
private String m_username;
private byte[] m_hashedPassword;
private int m_hashType;
// Time that the authentication session will expire
private long m_authExpiresAt;
/**
* Class constructor
*/
public NTLMPassthruToken()
{
// We do not know the username yet, and will not know the password
super("", "");
}
/**
* Return the challenge
*
* @return NTLMChallenge
*/
public final NTLMChallenge getChallenge()
{
return m_challenge;
}
/**
* Return the user account
*
* @return Object
*/
public final Object getPrincipal()
{
return m_username;
}
/**
* Return the hashed password
*
* @return byte[]
*/
public final byte[] getHashedPassword()
{
return m_hashedPassword;
}
/**
* Return the hashed password type
*
* @return int
*/
public final int getPasswordType()
{
return m_hashType;
}
/**
* Return the authentication expiry time, this will be zero if the authentication session has not yet
* been opened to the server
*
* @return long
*/
public final long getAuthenticationExpireTime()
{
return m_authExpiresAt;
}
/**
* Set the hashed password and type
*
* @param hashedPassword byte[]
* @param hashType int
*/
public final void setUserAndPassword(String username, byte[] hashedPassword, int hashType)
{
m_username = username.toLowerCase();
m_hashedPassword = hashedPassword;
m_hashType = hashType;
}
/**
* Set the challenge for this token
*
* @param challenge NTLMChallenge
*/
protected final void setChallenge(NTLMChallenge challenge)
{
m_challenge = challenge;
}
/**
* Set the authentication expire time, this indicates that an authentication session is associated with this
* token and the session will be closed if the authentication is not completed by this time.
*
* @param startTime long
*/
protected final void setAuthenticationExpireTime(long expireTime)
{
m_authExpiresAt = expireTime;
}
/**
* Check for object equality
*
* @param obj Object
* @return boolean
*/
public boolean equals(Object obj)
{
// Only match on the same object
return this == obj;
}
}

View File

@@ -0,0 +1,344 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authentication.ntlm;
import java.util.Date;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
import org.alfresco.service.cmr.repository.NodeService;
import org.springframework.dao.DataAccessException;
/**
* Null Mutable Authentication Dao Class
*
* <p>Mutable authentication implementation that does nothing.
*
* @author GKSpencer
*/
public class NullMutableAuthenticationDao implements MutableAuthenticationDao
{
/**
* Method kept just for backward compatibility with older configurations that
* might have been passing in a value.
*
* @param nodeService ignored
*/
public void setNodeService(NodeService nodeService)
{
// do nothing
}
/**
* Create a user with the given userName and password
*
* @param userName
* @param rawPassword
* @throws AuthenticationException
*/
public void createUser(String userName, char[] rawPassword) throws AuthenticationException
{
throw new AlfrescoRuntimeException("Not implemented");
// Nothing to do
}
/**
* Update a user's password.
*
* @param userName
* @param rawPassword
* @throws AuthenticationException
*/
public void updateUser(String userName, char[] rawPassword) throws AuthenticationException
{
throw new AlfrescoRuntimeException("Not implemented");
// Nothing to do
}
/**
* Delete a user.
*
* @param userName
* @throws AuthenticationException
*/
public void deleteUser(String userName) throws AuthenticationException
{
throw new AlfrescoRuntimeException("Not implemented");
// Nothing to do
}
/**
* Check is a user exists.
*
* @param userName
* @return
*/
public boolean userExists(String userName)
{
return true;
}
/**
* Enable/disable a user.
*
* @param userName
* @param enabled
*/
public void setEnabled(String userName, boolean enabled)
{
throw new AlfrescoRuntimeException("Not implemented");
// Nothing to do
}
/**
* Getter for user enabled
*
* @param userName
* @return
*/
public boolean getEnabled(String userName)
{
throw new AlfrescoRuntimeException("Not implemented");
// return true;
}
/**
* Set if the account should expire
*
* @param userName
* @param expires
*/
public void setAccountExpires(String userName, boolean expires)
{
throw new AlfrescoRuntimeException("Not implemented");
// Nothing to do
}
/**
* Does the account expire?
*
* @param userName
* @return
*/
public boolean getAccountExpires(String userName)
{
throw new AlfrescoRuntimeException("Not implemented");
// return false;
}
/**
* Has the account expired?
*
* @param userName
* @return
*/
public boolean getAccountHasExpired(String userName)
{
throw new AlfrescoRuntimeException("Not implemented");
// return false;
}
/**
* Set if the password expires.
*
* @param userName
* @param expires
*/
public void setCredentialsExpire(String userName, boolean expires)
{
throw new AlfrescoRuntimeException("Not implemented");
// Nothing to do
}
/**
* Do the credentials for the user expire?
*
* @param userName
* @return
*/
public boolean getCredentialsExpire(String userName)
{
throw new AlfrescoRuntimeException("Not implemented");
// return false;
}
/**
* Have the credentials for the user expired?
*
* @param userName
* @return
*/
public boolean getCredentialsHaveExpired(String userName)
{
throw new AlfrescoRuntimeException("Not implemented");
// return false;
}
/**
* Set if the account is locked.
*
* @param userName
* @param locked
*/
public void setLocked(String userName, boolean locked)
{
throw new AlfrescoRuntimeException("Not implemented");
// Nothing to do
}
/**
* Is the account locked?
*
* @param userName
* @return
*/
public boolean getAccountlocked(String userName)
{
throw new AlfrescoRuntimeException("Not implemented");
// return false;
}
/**
* Set the date on which the account expires
*
* @param userName
* @param exipryDate
*/
public void setAccountExpiryDate(String userName, Date exipryDate)
{
throw new AlfrescoRuntimeException("Not implemented");
// Nothing to do
}
/**
* Get the date when this account expires.
*
* @param userName
* @return
*/
public Date getAccountExpiryDate(String userName)
{
throw new AlfrescoRuntimeException("Not implemented");
// return null;
}
/**
* Set the date when credentials expire.
*
* @param userName
* @param exipryDate
*/
public void setCredentialsExpiryDate(String userName, Date exipryDate)
{
throw new AlfrescoRuntimeException("Not implemented");
// Nothing to do
}
/**
* Get the date when the credentials/password expire.
*
* @param userName
* @return
*/
public Date getCredentialsExpiryDate(String userName)
{
throw new AlfrescoRuntimeException("Not implemented");
// return null;
}
/**
* Get the MD4 password hash
*
* @param userName
* @return
*/
public String getMD4HashedPassword(String userName)
{
throw new AlfrescoRuntimeException("Not implemented");
// return null;
}
/**
* Are user names case sensitive?
*
* @return
*/
public boolean getUserNamesAreCaseSensitive()
{
throw new AlfrescoRuntimeException("Not implemented");
// return false;
}
/**
* Return the user details for the specified user
*
* @param user String
* @return UserDetails
* @exception UsernameNotFoundException
* @exception DataAccessException
*/
public UserDetails loadUserByUsername(String arg0) throws UsernameNotFoundException, DataAccessException
{
throw new AlfrescoRuntimeException("Not implemented");
// return null;
}
/**
* Return salt for user
*
* @param user UserDetails
* @return Object
*/
public Object getSalt(UserDetails user)
{
throw new AlfrescoRuntimeException("Not implemented");
// return null;
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authority;
import java.util.Set;
import org.alfresco.service.cmr.security.AuthorityType;
public interface AuthorityDAO
{
/**
* Add an authority to another.
*
* @param parentName
* @param childName
*/
void addAuthority(String parentName, String childName);
/**
* Create an authority.
*
* @param parentName
* @param name
*/
void createAuthority(String parentName, String name);
/**
* Delete an authority.
*
* @param name
*/
void deleteAuthority(String name);
/**
* Get all root authorities.
*
* @param type
* @return
*/
Set<String> getAllRootAuthorities(AuthorityType type);
/**
* Get contained authorities.
*
* @param type
* @param name
* @param immediate
* @return
*/
Set<String> getContainedAuthorities(AuthorityType type, String name, boolean immediate);
/**
* Remove an authority.
*
* @param parentName
* @param childName
*/
void removeAuthority(String parentName, String childName);
/**
* Get the authorities that contain the one given.
*
* @param type
* @param name
* @param immediate
* @return
*/
Set<String> getContainingAuthorities(AuthorityType type, String name, boolean immediate);
/**
* Get all authorities by type
*
* @param type
* @return
*/
Set<String> getAllAuthorities(AuthorityType type);
}

View File

@@ -0,0 +1,488 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authority;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.search.impl.lucene.QueryParser;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.ISO9075;
public class AuthorityDAOImpl implements AuthorityDAO
{
private static final StoreRef STOREREF_USERS = new StoreRef("user", "alfrescoUserStore");
private NodeService nodeService;
private NamespacePrefixResolver namespacePrefixResolver;
private QName qnameAssocSystem;
private QName qnameAssocAuthorities;
private SearchService searchService;
private DictionaryService dictionaryService;
private SimpleCache<String, ArrayList<NodeRef>> userToAuthorityCache;
public AuthorityDAOImpl()
{
super();
}
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver)
{
this.namespacePrefixResolver = namespacePrefixResolver;
qnameAssocSystem = QName.createQName("sys", "system", namespacePrefixResolver);
qnameAssocAuthorities = QName.createQName("sys", "authorities", namespacePrefixResolver);
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
public void setUserToAuthorityCache(SimpleCache<String, ArrayList<NodeRef>> userToAuthorityCache)
{
this.userToAuthorityCache = userToAuthorityCache;
}
public void addAuthority(String parentName, String childName)
{
NodeRef parentRef = getAuthorityOrNull(parentName);
if (parentRef == null)
{
throw new UnknownAuthorityException("An authority was not found for " + parentName);
}
if (AuthorityType.getAuthorityType(childName).equals(AuthorityType.USER))
{
Collection<String> memberCollection = DefaultTypeConverter.INSTANCE.getCollection(String.class, nodeService
.getProperty(parentRef, ContentModel.PROP_MEMBERS));
HashSet<String> members = new HashSet<String>();
members.addAll(memberCollection);
members.add(childName);
nodeService.setProperty(parentRef, ContentModel.PROP_MEMBERS, members);
userToAuthorityCache.remove(childName);
}
else
{
NodeRef childRef = getAuthorityOrNull(childName);
if (childRef == null)
{
throw new UnknownAuthorityException("An authority was not found for " + childName);
}
nodeService.addChild(
parentRef,
childRef,
ContentModel.ASSOC_MEMBER,
QName.createQName("usr", childName, namespacePrefixResolver));
}
}
public void createAuthority(String parentName, String name)
{
HashMap<QName, Serializable> props = new HashMap<QName, Serializable>();
props.put(ContentModel.PROP_AUTHORITY_NAME, name);
if (parentName != null)
{
NodeRef parentRef = getAuthorityOrNull(parentName);
if (parentRef == null)
{
throw new UnknownAuthorityException("An authority was not found for " + parentName);
}
nodeService.createNode(
parentRef,
ContentModel.ASSOC_MEMBER,
QName.createQName("usr", name, namespacePrefixResolver),
ContentModel.TYPE_AUTHORITY_CONTAINER,
props);
}
else
{
NodeRef authorityContainerRef = getAuthorityContainer();
nodeService.createNode(
authorityContainerRef,
ContentModel.ASSOC_MEMBER,
QName.createQName("usr", name, namespacePrefixResolver),
ContentModel.TYPE_AUTHORITY_CONTAINER,
props);
}
}
public void deleteAuthority(String name)
{
NodeRef nodeRef = getAuthorityOrNull(name);
if (nodeRef == null)
{
throw new UnknownAuthorityException("An authority was not found for " + name);
}
nodeService.deleteNode(nodeRef);
}
public Set<String> getAllRootAuthorities(AuthorityType type)
{
HashSet<String> authorities = new HashSet<String>();
NodeRef container = getAuthorityContainer();
if (container != null)
{
findAuthorities(type, container, authorities, false, false, false);
}
return authorities;
}
public Set<String> getAllAuthorities(AuthorityType type)
{
HashSet<String> authorities = new HashSet<String>();
NodeRef container = getAuthorityContainer();
if (container != null)
{
findAuthorities(type, container, authorities, false, true, false);
}
return authorities;
}
public Set<String> getContainedAuthorities(AuthorityType type, String name, boolean immediate)
{
if (AuthorityType.getAuthorityType(name).equals(AuthorityType.USER))
{
return Collections.<String> emptySet();
}
else
{
NodeRef nodeRef = getAuthorityOrNull(name);
if (nodeRef == null)
{
throw new UnknownAuthorityException("An authority was not found for " + name);
}
HashSet<String> authorities = new HashSet<String>();
findAuthorities(type, nodeRef, authorities, false, !immediate, false);
return authorities;
}
}
public void removeAuthority(String parentName, String childName)
{
NodeRef parentRef = getAuthorityOrNull(parentName);
if (parentRef == null)
{
throw new UnknownAuthorityException("An authority was not found for " + parentName);
}
if (AuthorityType.getAuthorityType(childName).equals(AuthorityType.USER))
{
Collection<String> memberCollection = DefaultTypeConverter.INSTANCE.getCollection(String.class, nodeService
.getProperty(parentRef, ContentModel.PROP_MEMBERS));
HashSet<String> members = new HashSet<String>();
members.addAll(memberCollection);
members.remove(childName);
nodeService.setProperty(parentRef, ContentModel.PROP_MEMBERS, members);
userToAuthorityCache.remove(childName);
}
else
{
NodeRef childRef = getAuthorityOrNull(childName);
if (childRef == null)
{
throw new UnknownAuthorityException("An authority was not found for " + childName);
}
nodeService.removeChild(parentRef, childRef);
}
}
public Set<String> getContainingAuthorities(AuthorityType type, String name, boolean immediate)
{
HashSet<String> authorities = new HashSet<String>();
findAuthorities(type, name, authorities, true, !immediate);
return authorities;
}
private void findAuthorities(AuthorityType type, String name, Set<String> authorities, boolean parents,
boolean recursive)
{
if (AuthorityType.getAuthorityType(name).equals(AuthorityType.GUEST))
{
// Nothing to do
}
else if (AuthorityType.getAuthorityType(name).equals(AuthorityType.USER))
{
for (NodeRef ref : getUserContainers(name))
{
findAuthorities(type, ref, authorities, parents, recursive, true);
}
}
else
{
NodeRef ref = getAuthorityOrNull(name);
if (ref == null)
{
throw new UnknownAuthorityException("An authority was not found for " + name);
}
findAuthorities(type, ref, authorities, parents, recursive, false);
}
}
private ArrayList<NodeRef> getUserContainers(String name)
{
ArrayList<NodeRef> containers = userToAuthorityCache.get(name);
if (containers == null)
{
containers = findUserContainers(name);
userToAuthorityCache.put(name, containers);
}
return containers;
}
private ArrayList<NodeRef> findUserContainers(String name)
{
SearchParameters sp = new SearchParameters();
sp.addStore(STOREREF_USERS);
sp.setLanguage("lucene");
sp.setQuery("+TYPE:\""
+ ContentModel.TYPE_AUTHORITY_CONTAINER
+ "\""
+ " +@"
+ QueryParser.escape("{"
+ ContentModel.PROP_MEMBERS.getNamespaceURI() + "}"
+ ISO9075.encode(ContentModel.PROP_MEMBERS.getLocalName())) + ":\"" + name + "\"");
ResultSet rs = null;
try
{
rs = searchService.query(sp);
ArrayList<NodeRef> answer = new ArrayList<NodeRef>(rs.length());
for (ResultSetRow row : rs)
{
answer.add(row.getNodeRef());
}
return answer;
}
finally
{
if (rs != null)
{
rs.close();
}
}
}
private void findAuthorities(AuthorityType type, NodeRef nodeRef, Set<String> authorities, boolean parents,
boolean recursive, boolean includeNode)
{
List<ChildAssociationRef> cars = parents ? nodeService.getParentAssocs(nodeRef) : nodeService
.getChildAssocs(nodeRef);
if (includeNode)
{
String authorityName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef,
ContentModel.PROP_AUTHORITY_NAME));
if (type == null)
{
authorities.add(authorityName);
}
else
{
AuthorityType authorityType = AuthorityType.getAuthorityType(authorityName);
if (authorityType.equals(type))
{
authorities.add(authorityName);
}
}
}
// Loop over children
for (ChildAssociationRef car : cars)
{
NodeRef current = parents ? car.getParentRef() : car.getChildRef();
QName currentType = nodeService.getType(current);
if (dictionaryService.isSubClass(currentType, ContentModel.TYPE_AUTHORITY))
{
String authorityName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(
current, ContentModel.PROP_AUTHORITY_NAME));
if (type == null)
{
authorities.add(authorityName);
if (recursive)
{
findAuthorities(type, current, authorities, parents, recursive, false);
}
}
else
{
AuthorityType authorityType = AuthorityType.getAuthorityType(authorityName);
if (authorityType.equals(type))
{
authorities.add(authorityName);
}
if (recursive)
{
findAuthorities(type, current, authorities, parents, recursive, false);
}
}
}
}
// loop over properties
if (!parents)
{
Collection<String> members = DefaultTypeConverter.INSTANCE.getCollection(String.class, nodeService
.getProperty(nodeRef, ContentModel.PROP_MEMBERS));
if (members != null)
{
for (String user : members)
{
if (user != null)
{
if (type == null)
{
authorities.add(user);
}
else
{
AuthorityType authorityType = AuthorityType.getAuthorityType(user);
if (authorityType.equals(type))
{
authorities.add(user);
}
}
}
}
}
}
}
private NodeRef getAuthorityOrNull(String name)
{
SearchParameters sp = new SearchParameters();
sp.addStore(STOREREF_USERS);
sp.setLanguage("lucene");
sp.setQuery("+TYPE:\""
+ ContentModel.TYPE_AUTHORITY_CONTAINER
+ "\""
+ " +@"
+ QueryParser.escape("{"
+ ContentModel.PROP_AUTHORITY_NAME.getNamespaceURI() + "}"
+ ISO9075.encode(ContentModel.PROP_AUTHORITY_NAME.getLocalName())) + ":\"" + name + "\"");
ResultSet rs = null;
try
{
rs = searchService.query(sp);
if (rs.length() == 0)
{
return null;
}
else
{
for (ResultSetRow row : rs)
{
String test = DefaultTypeConverter.INSTANCE.convert(
String.class,
nodeService.getProperty(row.getNodeRef(), ContentModel.PROP_AUTHORITY_NAME));
if (test.equals(name))
{
return row.getNodeRef();
}
}
}
return null;
}
finally
{
if (rs != null)
{
rs.close();
}
}
}
/**
* @return Returns the authority container, <b>which must exist</b>
*/
private NodeRef getAuthorityContainer()
{
NodeRef rootNodeRef = nodeService.getRootNode(STOREREF_USERS);
List<ChildAssociationRef> results = nodeService.getChildAssocs(
rootNodeRef,
RegexQNamePattern.MATCH_ALL,
qnameAssocSystem);
NodeRef sysNodeRef = null;
if (results.size() == 0)
{
throw new AlfrescoRuntimeException("Required authority system path not found: " + qnameAssocSystem);
}
else
{
sysNodeRef = results.get(0).getChildRef();
}
results = nodeService.getChildAssocs(
sysNodeRef,
RegexQNamePattern.MATCH_ALL,
qnameAssocAuthorities);
NodeRef authNodeRef = null;
if (results.size() == 0)
{
throw new AlfrescoRuntimeException("Required authority path not found: " + qnameAssocAuthorities);
}
else
{
authNodeRef = results.get(0).getChildRef();
}
return authNodeRef;
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authority;
import org.alfresco.error.AlfrescoRuntimeException;
public class AuthorityException extends AlfrescoRuntimeException
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = -5367993045129604445L;
public AuthorityException(String msgId)
{
super(msgId);
}
public AuthorityException(String msgId, Object[] msgParams)
{
super(msgId, msgParams);
}
public AuthorityException(String msgId, Throwable cause)
{
super(msgId, cause);
}
public AuthorityException(String msgId, Object[] msgParams, Throwable cause)
{
super(msgId, msgParams, cause);
}
}

View File

@@ -0,0 +1,251 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authority;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.permissions.PermissionServiceSPI;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
/**
* The default implementation of the authority service.
*
* @author Andy Hind
*/
public class AuthorityServiceImpl implements AuthorityService
{
private PersonService personService;
private NodeService nodeService;
private AuthorityDAO authorityDAO;
private PermissionServiceSPI permissionServiceSPI;
private Set<String> adminSet = Collections.singleton(PermissionService.ADMINISTRATOR_AUTHORITY);
private Set<String> guestSet = Collections.singleton(PermissionService.GUEST_AUTHORITY);
private Set<String> allSet = Collections.singleton(PermissionService.ALL_AUTHORITIES);
private Set<String> adminUsers;
private AuthenticationComponent authenticationComponent;
public AuthorityServiceImpl()
{
super();
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
public void setAuthorityDAO(AuthorityDAO authorityDAO)
{
this.authorityDAO = authorityDAO;
}
public void setPermissionServiceSPI(PermissionServiceSPI permissionServiceSPI)
{
this.permissionServiceSPI = permissionServiceSPI;
}
/**
* Currently the admin authority is granted only to the ALFRESCO_ADMIN_USER
* user.
*/
public boolean hasAdminAuthority()
{
String currentUserName = authenticationComponent.getCurrentUserName();
return ((currentUserName != null) && adminUsers.contains(currentUserName));
}
// IOC
public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
{
this.authenticationComponent = authenticationComponent;
}
public void setAdminUsers(Set<String> adminUsers)
{
this.adminUsers = adminUsers;
}
public Set<String> getAuthorities()
{
Set<String> authorities = new HashSet<String>();
String currentUserName = authenticationComponent.getCurrentUserName();
if (adminUsers.contains(currentUserName))
{
authorities.addAll(adminSet);
}
if(AuthorityType.getAuthorityType(currentUserName) != AuthorityType.GUEST)
{
authorities.addAll(allSet);
}
authorities.addAll(getContainingAuthorities(null, currentUserName, false));
return authorities;
}
public Set<String> getAllAuthorities(AuthorityType type)
{
Set<String> authorities = new HashSet<String>();
switch (type)
{
case ADMIN:
authorities.addAll(adminSet);
break;
case EVERYONE:
authorities.addAll(allSet);
break;
case GUEST:
authorities.addAll(guestSet);
break;
case GROUP:
authorities.addAll(authorityDAO.getAllAuthorities(type));
break;
case OWNER:
break;
case ROLE:
authorities.addAll(authorityDAO.getAllAuthorities(type));
break;
case USER:
for (NodeRef personRef : personService.getAllPeople())
{
authorities.add(DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(personRef,
ContentModel.PROP_USERNAME)));
}
break;
default:
break;
}
return authorities;
}
public void addAuthority(String parentName, String childName)
{
authorityDAO.addAuthority(parentName, childName);
}
private void checkTypeIsMutable(AuthorityType type)
{
if((type == AuthorityType.GROUP) || (type == AuthorityType.ROLE))
{
return;
}
else
{
throw new AuthorityException("Trying to modify a fixed authority");
}
}
public String createAuthority(AuthorityType type, String parentName, String shortName)
{
checkTypeIsMutable(type);
String name = getName(type, shortName);
authorityDAO.createAuthority(parentName, name);
return name;
}
public void deleteAuthority(String name)
{
AuthorityType type = AuthorityType.getAuthorityType(name);
checkTypeIsMutable(type);
authorityDAO.deleteAuthority(name);
permissionServiceSPI.deletePermissions(name);
}
public Set<String> getAllRootAuthorities(AuthorityType type)
{
return authorityDAO.getAllRootAuthorities(type);
}
public Set<String> getContainedAuthorities(AuthorityType type, String name, boolean immediate)
{
return authorityDAO.getContainedAuthorities(type, name, immediate);
}
public Set<String> getContainingAuthorities(AuthorityType type, String name, boolean immediate)
{
return authorityDAO.getContainingAuthorities(type, name, immediate);
}
public String getName(AuthorityType type, String shortName)
{
if (type.isFixedString())
{
return type.getFixedString();
}
else if (type.isPrefixed())
{
return type.getPrefixString() + shortName;
}
else
{
return shortName;
}
}
public String getShortName(String name)
{
AuthorityType type = AuthorityType.getAuthorityType(name);
if (type.isFixedString())
{
return "";
}
else if (type.isPrefixed())
{
return name.substring(type.getPrefixString().length());
}
else
{
return name;
}
}
public void removeAuthority(String parentName, String childName)
{
authorityDAO.removeAuthority(parentName, childName);
}
}

View File

@@ -0,0 +1,517 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authority;
import javax.transaction.UserTransaction;
import junit.framework.TestCase;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ApplicationContext;
public class AuthorityServiceTest extends TestCase
{
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private AuthenticationComponent authenticationComponent;
private AuthenticationComponent authenticationComponentImpl;
private AuthenticationService authenticationService;
private MutableAuthenticationDao authenticationDAO;
private AuthorityService authorityService;
private AuthorityService pubAuthorityService;
private PersonService personService;
private UserTransaction tx;
public AuthorityServiceTest()
{
super();
}
public void setUp() throws Exception
{
authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
authenticationComponentImpl = (AuthenticationComponent) ctx.getBean("authenticationComponentImpl");
authenticationService = (AuthenticationService) ctx.getBean("authenticationService");
authorityService = (AuthorityService) ctx.getBean("authorityService");
pubAuthorityService = (AuthorityService) ctx.getBean("AuthorityService");
personService = (PersonService) ctx.getBean("personService");
authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao");
authenticationComponentImpl.setSystemUserAsCurrentUser();
TransactionService transactionService = (TransactionService) ctx.getBean(ServiceRegistry.TRANSACTION_SERVICE
.getLocalName());
tx = transactionService.getUserTransaction();
tx.begin();
if (!authenticationDAO.userExists("andy"))
{
authenticationService.createAuthentication("andy", "andy".toCharArray());
}
if (!authenticationDAO.userExists("admin"))
{
authenticationService.createAuthentication("admin", "admin".toCharArray());
}
if (!authenticationDAO.userExists("administrator"))
{
authenticationService.createAuthentication("administrator", "administrator".toCharArray());
}
}
@Override
protected void tearDown() throws Exception
{
authenticationComponentImpl.clearCurrentSecurityContext();
tx.rollback();
super.tearDown();
}
public void testNonAdminUser()
{
authenticationComponent.setCurrentUser("andy");
assertFalse(authorityService.hasAdminAuthority());
assertFalse(pubAuthorityService.hasAdminAuthority());
assertEquals(1, authorityService.getAuthorities().size());
}
public void testAdminUser()
{
authenticationComponent.setCurrentUser("admin");
assertTrue(authorityService.hasAdminAuthority());
assertTrue(pubAuthorityService.hasAdminAuthority());
assertEquals(2, authorityService.getAuthorities().size());
authenticationComponent.setCurrentUser("administrator");
assertTrue(authorityService.hasAdminAuthority());
assertTrue(pubAuthorityService.hasAdminAuthority());
assertEquals(2, authorityService.getAuthorities().size());
}
public void testAuthorities()
{
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.ADMIN).size());
assertTrue(pubAuthorityService.getAllAuthorities(AuthorityType.ADMIN).contains(
PermissionService.ADMINISTRATOR_AUTHORITY));
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.EVERYONE).size());
assertTrue(pubAuthorityService.getAllAuthorities(AuthorityType.EVERYONE).contains(
PermissionService.ALL_AUTHORITIES));
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertFalse(pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).contains(
PermissionService.ALL_AUTHORITIES));
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.GUEST).size());
assertTrue(pubAuthorityService.getAllAuthorities(AuthorityType.GUEST).contains(PermissionService.GUEST_AUTHORITY));
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.OWNER).size());
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(personService.getAllPeople().size(), pubAuthorityService.getAllAuthorities(AuthorityType.USER)
.size());
}
public void testCreateAdminAuth()
{
try
{
pubAuthorityService.createAuthority(AuthorityType.ADMIN, null, "woof");
fail("Should not be able to create an admin authority");
}
catch (AuthorityException ae)
{
}
}
public void testCreateEveryoneAuth()
{
try
{
pubAuthorityService.createAuthority(AuthorityType.EVERYONE, null, "woof");
fail("Should not be able to create an everyone authority");
}
catch (AuthorityException ae)
{
}
}
public void testCreateGuestAuth()
{
try
{
pubAuthorityService.createAuthority(AuthorityType.GUEST, null, "woof");
fail("Should not be able to create an guest authority");
}
catch (AuthorityException ae)
{
}
}
public void testCreateOwnerAuth()
{
try
{
pubAuthorityService.createAuthority(AuthorityType.OWNER, null, "woof");
fail("Should not be able to create an owner authority");
}
catch (AuthorityException ae)
{
}
}
public void testCreateUserAuth()
{
try
{
pubAuthorityService.createAuthority(AuthorityType.USER, null, "woof");
fail("Should not be able to create an user authority");
}
catch (AuthorityException ae)
{
}
}
public void testCreateRootAuth()
{
String auth;
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "woof");
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(1, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
pubAuthorityService.deleteAuthority(auth);
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
auth = pubAuthorityService.createAuthority(AuthorityType.ROLE, null, "woof");
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(1, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
pubAuthorityService.deleteAuthority(auth);
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
}
public void testCreateAuth()
{
String auth1;
String auth2;
String auth3;
String auth4;
String auth5;
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth1 = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "one");
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(1, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth2 = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "two");
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth3 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth1, "three");
assertEquals(3, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth4 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth1, "four");
assertEquals(4, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth5 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth2, "five");
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
pubAuthorityService.deleteAuthority(auth5);
assertEquals(4, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
pubAuthorityService.deleteAuthority(auth4);
assertEquals(3, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
pubAuthorityService.deleteAuthority(auth3);
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
pubAuthorityService.deleteAuthority(auth2);
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(1, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
pubAuthorityService.deleteAuthority(auth1);
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
auth1 = pubAuthorityService.createAuthority(AuthorityType.ROLE, null, "one");
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(1, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
auth2 = pubAuthorityService.createAuthority(AuthorityType.ROLE, null, "two");
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
auth3 = pubAuthorityService.createAuthority(AuthorityType.ROLE, auth1, "three");
assertEquals(3, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
auth4 = pubAuthorityService.createAuthority(AuthorityType.ROLE, auth1, "four");
assertEquals(4, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
auth5 = pubAuthorityService.createAuthority(AuthorityType.ROLE, auth2, "five");
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
pubAuthorityService.deleteAuthority(auth5);
assertEquals(4, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
pubAuthorityService.deleteAuthority(auth4);
assertEquals(3, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
pubAuthorityService.deleteAuthority(auth3);
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
pubAuthorityService.deleteAuthority(auth2);
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(1, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
pubAuthorityService.deleteAuthority(auth1);
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.ROLE).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.ROLE).size());
}
public void testCreateAuthTree()
{
String auth1;
String auth2;
String auth3;
String auth4;
String auth5;
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth1 = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "one");
assertEquals("GROUP_one", auth1);
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(1, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth2 = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "two");
assertEquals("GROUP_two", auth2);
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth3 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth1, "three");
assertEquals("GROUP_three", auth3);
assertEquals(3, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth4 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth1, "four");
assertEquals("GROUP_four", auth4);
assertEquals(4, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth5 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth2, "five");
assertEquals("GROUP_five", auth5);
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.USER).size());
pubAuthorityService.addAuthority(auth5, "andy");
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
// The next call looks for people not users :-)
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.USER).size());
assertEquals(2, pubAuthorityService.getContainingAuthorities(null, "andy", false).size());
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth5));
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth2));
assertEquals(1, pubAuthorityService.getContainingAuthorities(null, auth5, false).size());
assertTrue(pubAuthorityService.getContainingAuthorities(null, auth5, false).contains(auth2));
assertEquals(2, pubAuthorityService.getContainedAuthorities(null, auth2, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains(auth5));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains("andy"));
assertEquals(1, pubAuthorityService.getContainedAuthorities(null, auth5, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth5, false).contains("andy"));
pubAuthorityService.removeAuthority(auth5, "andy");
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
// The next call looks for people not users :-)
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.USER).size());
assertEquals(0, pubAuthorityService.getContainingAuthorities(null, "andy", false).size());
assertEquals(1, pubAuthorityService.getContainingAuthorities(null, auth5, false).size());
assertTrue(pubAuthorityService.getContainingAuthorities(null, auth5, false).contains(auth2));
assertEquals(1, pubAuthorityService.getContainedAuthorities(null, auth2, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains(auth5));
assertEquals(0, pubAuthorityService.getContainedAuthorities(null, auth5, false).size());
}
public void testCreateAuthNet()
{
String auth1;
String auth2;
String auth3;
String auth4;
String auth5;
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth1 = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "one");
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(1, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth2 = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "two");
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth3 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth1, "three");
assertEquals(3, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth4 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth1, "four");
assertEquals(4, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth5 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth2, "five");
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.USER).size());
pubAuthorityService.addAuthority(auth5, "andy");
pubAuthorityService.addAuthority(auth1, "andy");
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
// The next call looks for people not users :-)
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.USER).size());
assertEquals(3, pubAuthorityService.getContainingAuthorities(null, "andy", false).size());
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth5));
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth2));
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth1));
assertEquals(2, pubAuthorityService.getContainedAuthorities(null, auth2, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains(auth5));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains("andy"));
assertEquals(3, pubAuthorityService.getContainedAuthorities(null, auth1, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth3));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth4));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains("andy"));
pubAuthorityService.removeAuthority(auth1, "andy");
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
// The next call looks for people not users :-)
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.USER).size());
assertEquals(2, pubAuthorityService.getContainingAuthorities(null, "andy", false).size());
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth5));
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth2));
assertEquals(2, pubAuthorityService.getContainedAuthorities(null, auth2, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains(auth5));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains("andy"));
assertEquals(2, pubAuthorityService.getContainedAuthorities(null, auth1, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth3));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth4));
}
public void testCreateAuthNet2()
{
String auth1;
String auth2;
String auth3;
String auth4;
String auth5;
assertEquals(0, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(0, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth1 = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "one");
assertEquals(1, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(1, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth2 = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "two");
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth3 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth1, "three");
assertEquals(3, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth4 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth1, "four");
assertEquals(4, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
auth5 = pubAuthorityService.createAuthority(AuthorityType.GROUP, auth2, "five");
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.USER).size());
pubAuthorityService.addAuthority(auth5, "andy");
pubAuthorityService.addAuthority(auth1, "andy");
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
// The next call looks for people not users :-)
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.USER).size());
assertEquals(3, pubAuthorityService.getContainingAuthorities(null, "andy", false).size());
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth5));
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth2));
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth1));
assertEquals(2, pubAuthorityService.getContainedAuthorities(null, auth2, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains(auth5));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains("andy"));
assertEquals(3, pubAuthorityService.getContainedAuthorities(null, auth1, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth3));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth4));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains("andy"));
pubAuthorityService.addAuthority(auth3, auth2);
assertEquals(5, pubAuthorityService.getAllAuthorities(AuthorityType.GROUP).size());
assertEquals(2, pubAuthorityService.getAllRootAuthorities(AuthorityType.GROUP).size());
// The next call looks for people not users :-)
assertEquals(2, pubAuthorityService.getAllAuthorities(AuthorityType.USER).size());
assertEquals(4, pubAuthorityService.getContainingAuthorities(null, "andy", false).size());
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth5));
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth2));
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth1));
assertTrue(pubAuthorityService.getContainingAuthorities(null, "andy", false).contains(auth3));
assertEquals(2, pubAuthorityService.getContainedAuthorities(null, auth2, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains(auth5));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth2, false).contains("andy"));
assertEquals(5, pubAuthorityService.getContainedAuthorities(null, auth1, false).size());
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth3));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth4));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth2));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains(auth5));
assertTrue(pubAuthorityService.getContainedAuthorities(null, auth1, false).contains("andy"));
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authority;
import org.alfresco.repo.security.permissions.impl.AbstractPermissionTest;
import org.alfresco.repo.security.permissions.impl.SimplePermissionEntry;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PermissionService;
public class ExtendedPermissionServiceTest extends AbstractPermissionTest
{
public void testGroupPermission()
{
runAs("andy");
assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ),
"GROUP_test", AccessStatus.ALLOWED));
assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
authorityService.createAuthority(AuthorityType.GROUP, null, "test");
authorityService.addAuthority("GROUP_test", "andy");
assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
authorityService.removeAuthority("GROUP_test", "andy");
assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
permissionService.clearPermission(rootNodeRef, "andy");
}
public void testDeletePermissionByRecipient()
{
runAs("andy");
assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ),
"GROUP_test", AccessStatus.ALLOWED));
assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
authorityService.createAuthority(AuthorityType.GROUP, null, "test");
authorityService.addAuthority("GROUP_test", "andy");
assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
permissionService.deletePermissions("GROUP_test");
assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.security.authority;
public class UnknownAuthorityException extends AuthorityException
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 4639634037108317201L;
public UnknownAuthorityException(String msgId)
{
super(msgId);
}
public UnknownAuthorityException(String msgId, Object[] msgParams)
{
super(msgId, msgParams);
}
public UnknownAuthorityException(String msgId, Throwable cause)
{
super(msgId, cause);
}
public UnknownAuthorityException(String msgId, Object[] msgParams, Throwable cause)
{
super(msgId, msgParams, cause);
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.repo.transaction;
import java.util.Properties;
import javax.transaction.TransactionManager;
import org.jboss.cache.TransactionManagerLookup;
import org.springframework.jndi.JndiObjectFactoryBean;
import org.springframework.jndi.JndiTemplate;
/**
* Helper lookup class to supply JBoss components with a <code>TransactionManager</code>.
* <p>
* The <code>JBossTransactionManagerLookup</code> will work when Alfresco is running in JBoss,
* but the <code>TreeCache</code> can be used within other containers; there might not be any
* container and the <code>TransactionManager</code> may held in a local JNDI tree.
* <p>
* For compatibility with other app servers, the JBoss <code>GenericTransactionManagerLookup</code>
* could also be used.
* <p>
* The default constructor configures the object to look in <b>java:/TransactionManager</b>
* for a <code>TransactionManager</code>. The only customisation that should be required is
* to change the {@link #setJndiName(String) jndiName} property. If more JNDI details need
* changing, then the actual {@link #setJndiLookup(JndiObjectFactoryBean) jndiLookup object} can
* be substituted with a customized version.
*
* @author Derek Hulley
*/
public class TransactionManagerJndiLookup implements TransactionManagerLookup
{
public static final String DEFAULT_JNDI_NAME = "java:/TransactionManager";
private JndiObjectFactoryBean jndiLookup;
public TransactionManagerJndiLookup()
{
jndiLookup = new JndiObjectFactoryBean();
jndiLookup.setJndiName(DEFAULT_JNDI_NAME);
jndiLookup.setProxyInterface(TransactionManager.class);
}
/**
* @see org.springframework.jndi.JndiAccessor#setJndiTemplate(org.springframework.jndi.JndiTemplate)
*/
public void setJndiTemplate(JndiTemplate jndiTemplate)
{
this.jndiLookup.setJndiTemplate(jndiTemplate);
}
/**
* @see org.springframework.jndi.JndiAccessor#setJndiEnvironment(java.util.Properties)
*/
public void setJndiEnvironment(Properties jndiEnvironment)
{
this.jndiLookup.setJndiEnvironment(jndiEnvironment);
}
/**
* Set the JNDI location where the <code>TransactionManager</code> can be found.
*
* @param jndiName
*/
public void setJndiName(String jndiName)
{
jndiLookup.setJndiName(jndiName);
}
/**
* @return Returns a <code>TransactionManager</code> looked up at the JNDI location
*/
public TransactionManager getTransactionManager() throws Exception
{
return (TransactionManager) jndiLookup.getObject();
}
}