diff --git a/config/alfresco/authority-services-context.xml b/config/alfresco/authority-services-context.xml
index 0cfee86d48..06bb7fc42c 100644
--- a/config/alfresco/authority-services-context.xml
+++ b/config/alfresco/authority-services-context.xml
@@ -7,12 +7,12 @@
-
+
+
-
-
-
+
+
@@ -22,6 +22,12 @@
+
+
+
+
+
+
@@ -42,4 +48,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/desktop/Alfresco.exe b/config/alfresco/desktop/Alfresco.exe
new file mode 100644
index 0000000000..1afb081373
Binary files /dev/null and b/config/alfresco/desktop/Alfresco.exe differ
diff --git a/config/alfresco/extension/chaining-authentication-context.xml.sample b/config/alfresco/extension/chaining-authentication-context.xml.sample
new file mode 100644
index 0000000000..f73a4a09b1
--- /dev/null
+++ b/config/alfresco/extension/chaining-authentication-context.xml.sample
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${user.name.caseSensitive}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ COMPANY.COM
+
+
+ Alfresco
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/extension/jaas-authentication-context.xml.sample b/config/alfresco/extension/jaas-authentication-context.xml.sample
new file mode 100644
index 0000000000..75dfe6b25d
--- /dev/null
+++ b/config/alfresco/extension/jaas-authentication-context.xml.sample
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+ DEFAULT.REALM
+
+
+ Alfresco
+
+
+
+
+
+
+ org.alfresco.repo.security.authentication.MutableAuthenticationDao
+
+
+
+
+
+
+
+
+
+
+ ${server.transaction.mode.default}
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/extension/ldap-authentication-context.xml.sample b/config/alfresco/extension/ldap-authentication-context.xml.sample
new file mode 100644
index 0000000000..f50725c1a9
--- /dev/null
+++ b/config/alfresco/extension/ldap-authentication-context.xml.sample
@@ -0,0 +1,442 @@
+
+
+
+
+
+
+
+
+
+ org.alfresco.repo.security.authentication.MutableAuthenticationDao
+
+
+
+
+
+
+
+
+
+ ${server.transaction.mode.default}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %s
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (objectclass=inetOrgPerson)
+
+
+
+
+ dc=alfresco,dc=org
+
+
+
+
+ uid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /app:company_home
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (objectclass=groupOfNames)
+
+
+
+
+ dc=alfresco,dc=org
+
+
+
+
+ uid
+
+
+
+
+ cn
+
+
+
+
+ groupOfNames
+
+
+
+
+ inetOrgPerson
+
+
+
+
+
+
+
+
+
+
+ member
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.alfresco.repo.importer.ImporterJob
+
+
+
+
+
+
+
+
+ 30000
+
+
+
+ 3600000
+
+
+
+
+
+
+
+
+ org.alfresco.repo.importer.ImporterJob
+
+
+
+
+
+
+
+
+ 30000
+
+
+
+ 3600000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${spaces.store}
+
+
+
+
+ /${system.system_container.childname}/${system.people_container.childname}
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${alfresco_user_store.store}
+
+
+
+
+ /${alfresco_user_store.system_container.childname}/${alfresco_user_store.authorities_container.childname}
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/extension/ntlm-authentication-context.xml.sample b/config/alfresco/extension/ntlm-authentication-context.xml.sample
new file mode 100644
index 0000000000..25967eb1fa
--- /dev/null
+++ b/config/alfresco/extension/ntlm-authentication-context.xml.sample
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+ false
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/extension/replicating-content-services-context.xml.sample b/config/alfresco/extension/replicating-content-services-context.xml.sample
new file mode 100644
index 0000000000..94ed1270cb
--- /dev/null
+++ b/config/alfresco/extension/replicating-content-services-context.xml.sample
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+ s:/backups/alfresco
+
+
+
+
+
+
+ fileContentStore
+
+
+
+ backupContentStore
+
+
+
+ true
+
+
+
+ 60
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/index-recovery-context.xml b/config/alfresco/index-recovery-context.xml
index 4d30ed0933..bad12938ae 100644
--- a/config/alfresco/index-recovery-context.xml
+++ b/config/alfresco/index-recovery-context.xml
@@ -2,23 +2,49 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+ workspace://SpacesStore
+ workspace://lightWeightVersionStore
+ user://alfrescoUserStore
-
+
+
+
+
+ false
+
+
+ false
+
+
+ 1000
+
+
+ NORMAL
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties
index d237e78d46..783db30183 100644
--- a/config/alfresco/version.properties
+++ b/config/alfresco/version.properties
@@ -7,7 +7,7 @@
version.major=1
version.minor=3
version.revision=0
-version.label=
+version.label=dev
# Edition label
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoApp.aps b/source/cpp/CAlfrescoApp/CAlfrescoApp.aps
new file mode 100644
index 0000000000..8e5c213a85
Binary files /dev/null and b/source/cpp/CAlfrescoApp/CAlfrescoApp.aps differ
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoApp.cpp b/source/cpp/CAlfrescoApp/CAlfrescoApp.cpp
new file mode 100644
index 0000000000..f39d06e0e4
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/CAlfrescoApp.cpp
@@ -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
+
+#include "util\String.h"
+#include "util\DataBuffer.h"
+#include "util\FileName.h"
+
+#include
+
+#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;
+}
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoApp.h b/source/cpp/CAlfrescoApp/CAlfrescoApp.h
new file mode 100644
index 0000000000..c618a04b84
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/CAlfrescoApp.h
@@ -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;
\ No newline at end of file
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoApp.htm b/source/cpp/CAlfrescoApp/CAlfrescoApp.htm
new file mode 100644
index 0000000000..237a093a41
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/CAlfrescoApp.htm
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+TODO: Place controls here.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoApp.ncb b/source/cpp/CAlfrescoApp/CAlfrescoApp.ncb
new file mode 100644
index 0000000000..39edd3a847
Binary files /dev/null and b/source/cpp/CAlfrescoApp/CAlfrescoApp.ncb differ
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoApp.rc b/source/cpp/CAlfrescoApp/CAlfrescoApp.rc
new file mode 100644
index 0000000000..b7dde5c0e6
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/CAlfrescoApp.rc
@@ -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
+
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoApp.sln b/source/cpp/CAlfrescoApp/CAlfrescoApp.sln
new file mode 100644
index 0000000000..655f0d3159
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/CAlfrescoApp.sln
@@ -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
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoApp.suo b/source/cpp/CAlfrescoApp/CAlfrescoApp.suo
new file mode 100644
index 0000000000..75201f26f0
Binary files /dev/null and b/source/cpp/CAlfrescoApp/CAlfrescoApp.suo differ
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoApp.vcproj b/source/cpp/CAlfrescoApp/CAlfrescoApp.vcproj
new file mode 100644
index 0000000000..371ce42ead
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/CAlfrescoApp.vcproj
@@ -0,0 +1,294 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoAppDlg.cpp b/source/cpp/CAlfrescoApp/CAlfrescoAppDlg.cpp
new file mode 100644
index 0000000000..8843b0bfa4
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/CAlfrescoAppDlg.cpp
@@ -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(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(m_hIcon);
+}
diff --git a/source/cpp/CAlfrescoApp/CAlfrescoAppDlg.h b/source/cpp/CAlfrescoApp/CAlfrescoAppDlg.h
new file mode 100644
index 0000000000..9fb2082e16
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/CAlfrescoAppDlg.h
@@ -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:
+};
diff --git a/source/cpp/CAlfrescoApp/FileStatusDialog.cpp b/source/cpp/CAlfrescoApp/FileStatusDialog.cpp
new file mode 100644
index 0000000000..152884e714
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/FileStatusDialog.cpp
@@ -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
diff --git a/source/cpp/CAlfrescoApp/FileStatusDialog.h b/source/cpp/CAlfrescoApp/FileStatusDialog.h
new file mode 100644
index 0000000000..6ac3a53ac3
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/FileStatusDialog.h
@@ -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;
+};
diff --git a/source/cpp/CAlfrescoApp/FileStatusView.cpp b/source/cpp/CAlfrescoApp/FileStatusView.cpp
new file mode 100644
index 0000000000..2b552204ce
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/FileStatusView.cpp
@@ -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
diff --git a/source/cpp/CAlfrescoApp/FileStatusView.h b/source/cpp/CAlfrescoApp/FileStatusView.h
new file mode 100644
index 0000000000..066f367e55
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/FileStatusView.h
@@ -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()
+};
+
+
diff --git a/source/cpp/CAlfrescoApp/ReadMe.txt b/source/cpp/CAlfrescoApp/ReadMe.txt
new file mode 100644
index 0000000000..247ba918eb
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/ReadMe.txt
@@ -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.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/source/cpp/CAlfrescoApp/alfresco.ico b/source/cpp/CAlfrescoApp/alfresco.ico
new file mode 100644
index 0000000000..9307688a6c
Binary files /dev/null and b/source/cpp/CAlfrescoApp/alfresco.ico differ
diff --git a/source/cpp/CAlfrescoApp/includes/alfresco/Alfresco.hpp b/source/cpp/CAlfrescoApp/includes/alfresco/Alfresco.hpp
new file mode 100644
index 0000000000..1004731cda
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/alfresco/Alfresco.hpp
@@ -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
+#include
+
+#include
+#include
+#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 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 getList( void) { return m_list; }
+
+private:
+ // Instance variables
+ //
+ // List of file information objects
+
+ std::vector m_list;
+};
+
+#endif
diff --git a/source/cpp/CAlfrescoApp/includes/util/ByteArray.h b/source/cpp/CAlfrescoApp/includes/util/ByteArray.h
new file mode 100644
index 0000000000..e8269843da
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/ByteArray.h
@@ -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
+#include
+
+#include "util\Types.h"
+
+// Classes defined in this header file
+
+namespace Alfresco {
+ class ByteArray;
+
+ typedef std::auto_ptr 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
diff --git a/source/cpp/CAlfrescoApp/includes/util/DataBuffer.h b/source/cpp/CAlfrescoApp/includes/util/DataBuffer.h
new file mode 100644
index 0000000000..7bc250264b
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/DataBuffer.h
@@ -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 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
diff --git a/source/cpp/CAlfrescoApp/includes/util/DataPacker.h b/source/cpp/CAlfrescoApp/includes/util/DataPacker.h
new file mode 100644
index 0000000000..d9eb561a73
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/DataPacker.h
@@ -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
diff --git a/source/cpp/CAlfrescoApp/includes/util/Exception.h b/source/cpp/CAlfrescoApp/includes/util/Exception.h
new file mode 100644
index 0000000000..a22de7059e
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/Exception.h
@@ -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
\ No newline at end of file
diff --git a/source/cpp/CAlfrescoApp/includes/util/FileName.h b/source/cpp/CAlfrescoApp/includes/util/FileName.h
new file mode 100644
index 0000000000..3cb3442177
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/FileName.h
@@ -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
diff --git a/source/cpp/CAlfrescoApp/includes/util/Integer.h b/source/cpp/CAlfrescoApp/includes/util/Integer.h
new file mode 100644
index 0000000000..e08d7ebd2b
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/Integer.h
@@ -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
\ No newline at end of file
diff --git a/source/cpp/CAlfrescoApp/includes/util/JavaTypes.h b/source/cpp/CAlfrescoApp/includes/util/JavaTypes.h
new file mode 100644
index 0000000000..7a537405a7
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/JavaTypes.h
@@ -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
diff --git a/source/cpp/CAlfrescoApp/includes/util/Long.h b/source/cpp/CAlfrescoApp/includes/util/Long.h
new file mode 100644
index 0000000000..d51f5db42b
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/Long.h
@@ -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
+
+#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
\ No newline at end of file
diff --git a/source/cpp/CAlfrescoApp/includes/util/String.h b/source/cpp/CAlfrescoApp/includes/util/String.h
new file mode 100644
index 0000000000..52902445b4
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/String.h
@@ -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
+#include
+#include
+
+#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 m_list;
+};
+
+#endif
diff --git a/source/cpp/CAlfrescoApp/includes/util/System.h b/source/cpp/CAlfrescoApp/includes/util/System.h
new file mode 100644
index 0000000000..6fa1d686ed
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/System.h
@@ -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
\ No newline at end of file
diff --git a/source/cpp/CAlfrescoApp/includes/util/Types.h b/source/cpp/CAlfrescoApp/includes/util/Types.h
new file mode 100644
index 0000000000..67f431a88c
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/includes/util/Types.h
@@ -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
diff --git a/source/cpp/CAlfrescoApp/res/CAlfrescoApp.ico b/source/cpp/CAlfrescoApp/res/CAlfrescoApp.ico
new file mode 100644
index 0000000000..b9e83ab000
Binary files /dev/null and b/source/cpp/CAlfrescoApp/res/CAlfrescoApp.ico differ
diff --git a/source/cpp/CAlfrescoApp/res/CAlfrescoApp.manifest b/source/cpp/CAlfrescoApp/res/CAlfrescoApp.manifest
new file mode 100644
index 0000000000..024ac68133
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/res/CAlfrescoApp.manifest
@@ -0,0 +1,22 @@
+
+
+
+Your app description here
+
+
+
+
+
+
diff --git a/source/cpp/CAlfrescoApp/res/CAlfrescoApp.rc2 b/source/cpp/CAlfrescoApp/res/CAlfrescoApp.rc2
new file mode 100644
index 0000000000..87038a0bac
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/res/CAlfrescoApp.rc2
@@ -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...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/source/cpp/CAlfrescoApp/resource.h b/source/cpp/CAlfrescoApp/resource.h
new file mode 100644
index 0000000000..d88a6cfbd7
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/resource.h
@@ -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
diff --git a/source/cpp/CAlfrescoApp/source/AlfrescoApp.cpp b/source/cpp/CAlfrescoApp/source/AlfrescoApp.cpp
new file mode 100644
index 0000000000..1cb9ec954a
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/AlfrescoApp.cpp
@@ -0,0 +1,420 @@
+#include
+
+#include "alfresco\Alfresco.hpp"
+
+#include "util\String.h"
+#include "util\DataBuffer.h"
+#include "util\FileName.h"
+
+#include
+
+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 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;
+}
diff --git a/source/cpp/CAlfrescoApp/source/alfresco/Alfresco.cpp b/source/cpp/CAlfrescoApp/source/alfresco/Alfresco.cpp
new file mode 100644
index 0000000000..a657619c7a
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/alfresco/Alfresco.cpp
@@ -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
+
+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;
+}
diff --git a/source/cpp/CAlfrescoApp/source/util/ByteArray.cpp b/source/cpp/CAlfrescoApp/source/util/ByteArray.cpp
new file mode 100644
index 0000000000..032c6314cf
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/util/ByteArray.cpp
@@ -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
+
+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;
+}
diff --git a/source/cpp/CAlfrescoApp/source/util/DataBuffer.cpp b/source/cpp/CAlfrescoApp/source/util/DataBuffer.cpp
new file mode 100644
index 0000000000..5134d12442
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/util/DataBuffer.cpp
@@ -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);
+}
diff --git a/source/cpp/CAlfrescoApp/source/util/DataPacker.cpp b/source/cpp/CAlfrescoApp/source/util/DataPacker.cpp
new file mode 100644
index 0000000000..89eaf1f9dc
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/util/DataPacker.cpp
@@ -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
+#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;
+}
diff --git a/source/cpp/CAlfrescoApp/source/util/Exception.cpp b/source/cpp/CAlfrescoApp/source/util/Exception.cpp
new file mode 100644
index 0000000000..74e76464c2
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/util/Exception.cpp
@@ -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() {
+}
+
+
diff --git a/source/cpp/CAlfrescoApp/source/util/FileName.cpp b/source/cpp/CAlfrescoApp/source/util/FileName.cpp
new file mode 100644
index 0000000000..9906e0abd4
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/util/FileName.cpp
@@ -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;
+}
diff --git a/source/cpp/CAlfrescoApp/source/util/Integer.cpp b/source/cpp/CAlfrescoApp/source/util/Integer.cpp
new file mode 100644
index 0000000000..7fbea17220
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/util/Integer.cpp
@@ -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);
+}
diff --git a/source/cpp/CAlfrescoApp/source/util/Long.cpp b/source/cpp/CAlfrescoApp/source/util/Long.cpp
new file mode 100644
index 0000000000..623f6631b3
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/util/Long.cpp
@@ -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));
+}
diff --git a/source/cpp/CAlfrescoApp/source/util/String.cpp b/source/cpp/CAlfrescoApp/source/util/String.cpp
new file mode 100644
index 0000000000..986e4a556e
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/util/String.cpp
@@ -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::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::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::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::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;
+}
diff --git a/source/cpp/CAlfrescoApp/source/util/System.cpp b/source/cpp/CAlfrescoApp/source/util/System.cpp
new file mode 100644
index 0000000000..003e79f839
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/source/util/System.cpp
@@ -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
+
+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;
+}
\ No newline at end of file
diff --git a/source/cpp/CAlfrescoApp/stdafx.cpp b/source/cpp/CAlfrescoApp/stdafx.cpp
new file mode 100644
index 0000000000..23a4420cb9
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/stdafx.cpp
@@ -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"
+
+
diff --git a/source/cpp/CAlfrescoApp/stdafx.h b/source/cpp/CAlfrescoApp/stdafx.h
new file mode 100644
index 0000000000..1c0fed7e3d
--- /dev/null
+++ b/source/cpp/CAlfrescoApp/stdafx.h
@@ -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 // MFC core and standard components
+#include // MFC extensions
+#include // MFC Automation classes
+
+#include // MFC support for Internet Explorer 4 Common Controls
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include // MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+#include // HTML Dialogs
+#include
diff --git a/source/java/org/alfresco/repo/cache/TreeCacheAdapter.java b/source/java/org/alfresco/repo/cache/TreeCacheAdapter.java
new file mode 100644
index 0000000000..bfc6dcab26
--- /dev/null
+++ b/source/java/org/alfresco/repo/cache/TreeCacheAdapter.java
@@ -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 TreeCache support.
+ *
+ * @author Derek Hulley
+ */
+public class TreeCacheAdapter
+ implements SimpleCache
+{
+ 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);
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/cache/TreeCacheAdapterTest.java b/source/java/org/alfresco/repo/cache/TreeCacheAdapterTest.java
new file mode 100644
index 0000000000..4c1218abc1
--- /dev/null
+++ b/source/java/org/alfresco/repo/cache/TreeCacheAdapterTest.java
@@ -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 cache;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ treeCache = new TreeCache();
+ treeCache.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+ treeCache.start();
+
+ cache = new TreeCacheAdapter();
+ 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);
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/replication/ContentStoreReplicator.java b/source/java/org/alfresco/repo/content/replication/ContentStoreReplicator.java
new file mode 100644
index 0000000000..11a4733d7a
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/replication/ContentStoreReplicator.java
@@ -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.
+ *
+ * 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.
+ *
+ * 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 true. */
+ 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 sourceUrls = sourceStore.getUrls();
+ // get all the URLs from the target
+ Set 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.
+ *
+ * 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();
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/replication/ContentStoreReplicatorTest.java b/source/java/org/alfresco/repo/content/replication/ContentStoreReplicatorTest.java
new file mode 100644
index 0000000000..97854f2065
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/replication/ContentStoreReplicatorTest.java
@@ -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.
+ *
+ * Afterwards, some content is removed from the the target.
+ *
+ * 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 sourceUrls = sourceStore.getUrls();
+ Set targetUrls = targetStore.getUrls();
+
+ sourceUrls.containsAll(targetUrls);
+ targetUrls.contains(sourceUrls);
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java
new file mode 100644
index 0000000000..e6bced21de
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java
@@ -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;
+
+/**
+ * Replicating Content Store
+ *
+ * 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.
+ *
+ * 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 primary store.
+ * 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.
+ *
+ * It supports the notion of inbound and/or outbound replication, both of which can be
+ * operational at the same time.
+ *
+ * Outbound Replication
+ *
+ * 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 in-transaction.
+ *
+ * The {@link #setOutboundThreadPoolExecutor(boolean) outboundThreadPoolExecutor }
+ * property to enable asynchronous replication.
+ * 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.
+ *
+ * Inbound Replication
+ *
+ * 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.
+ * 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.
+ *
+ *
No Replication
+ *
+ * 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 secondaryStores;
+ private boolean inbound;
+ private boolean outbound;
+ private ThreadPoolExecutor outboundThreadPoolExecutor;
+
+ private Lock readLock;
+ private Lock writeLock;
+
+ /**
+ * Default constructor set inbound = false and outbound = true;
+ */
+ 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 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 getUrls(Date createdAfter, Date createdBefore) throws ContentIOException
+ {
+ Set urls = new HashSet(1024);
+
+ // add in URLs from primary store
+ Set primaryUrls = primaryStore.getUrls(createdAfter, createdBefore);
+ urls.addAll(primaryUrls);
+
+ // add in URLs from secondary stores (they are visible for reads)
+ for (ContentStore secondaryStore : secondaryStores)
+ {
+ Set 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.
+ *
+ * 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 stores;
+ private ContentWriter writer;
+ private ThreadPoolExecutor threadPoolExecutor;
+
+ public ReplicatingWriteListener(
+ List 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);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/replication/ReplicatingContentStoreTest.java b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStoreTest.java
new file mode 100644
index 0000000000..cdaf67c54f
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStoreTest.java
@@ -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.
+ *
+ * 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 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(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 not exist
+ */
+ private void checkForUrl(String contentUrl, boolean mustExist)
+ {
+ // check that the URL is present for each of the stores
+ for (ContentStore store : secondaryStores)
+ {
+ Set 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());
+
+ 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);
+ }
+}
diff --git a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java
new file mode 100644
index 0000000000..01dd7811a8
--- /dev/null
+++ b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java
@@ -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.
+ *
+ * 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.
+ *
+ * The following points are important:
+ *
+ *
+ * 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 NORMAL mode. REFRESH should be
+ * used where the server will still be accessed from some clients
+ * despite the database changing.
+ *
+ *
+ * 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.
+ *
+ *
+ *
+ * @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 node instances */
+ private NodeService nodeService;
+ /** the stores to reindex */
+ private List 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(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 storeRefStrings)
+ {
+ storeRefs.clear();
+ for (String storeRefStr : storeRefStrings)
+ {
+ StoreRef storeRef = new StoreRef(storeRefStr);
+ storeRefs.add(storeRef);
+ }
+ }
+
+ /**
+ * Set this to true to initiate the full index recovery.
+ *
+ * This used to default to true 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