Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
The API documentation of following versions are available:
* [[sof_1.0_9120|http://sof.sourceforge.net/api_1.0_9120/sof/html/]]
* [[sof_8070|http://sof.sourceforge.net/api_8070/html/]]
* [[sof_8050|http://sof.sourceforge.net/api_8050/html/]]
The API documentation of following versions are available:
* [[sof_1.0_9120|http://sof.sourceforge.net/api_1.0_9120/remote_sof/html/]]
* [[sof_remote_9070|http://sof.sourceforge.net/api_9070/html/]]
//SOF// (Service Oriented Framework) wants to help software developers to avoid developing monolithic software. The //SOF// framework allows to separate a software system in several small components which are communicating via clearly defined interfaces. Components can be started and stopped at runtime and the components are notified about the lifecycle of other components if necessary. //SOF// is implemented in standard C++ and provides an OS independent framework for developing component based software. The //SOF// API is very similar to the OSGI API (see [[OSGI|http://www.osgi.org]]).
''Note:''
* SOF names components (like OSGI) as bundles.
* Bundles can consist of one or several classes.
* Bundles can be also implemented as DLL (=''D''ynamic ''L''ink ''L''ibrary).
* Bundles are loaded, started and stopped by SOF.
* Each bundle can register zero or several services which can be tracked by other bundles.
* Each bundle can track (listen to) one or several services.
[img[http://farm4.static.flickr.com/3271/2477292881_b67f8ff660_o.png]]
//SOF// provides a framework for supporting software modularization. Software components called bundles can communicate via defined service interfaces with other bundles. For getting the reference of a service each bundle can register service listeners which observe the lifecyle of services.
//Remote SOF// represents an extension for //SOF//. That means services can not only be tracked and registered within the same //SOF// container (=process) but across several processes whereas CORBA is used as communication layer.
[img[http://farm3.static.flickr.com/2481/3566511834_427819b320_o.png]]
The diagram above shows the simplified architecture of //Remote SOF//. There exist several //SOF// processes (here two) and every //SOF// process hosts several bundles. Bundles are able to register services and service listeners (just as with //SOF//) at the registry component of each //SOF// container. So far there is no big difference to the //SOF// framework. But for notifying other //SOF// processes about (de)registered services and service listeners all calls to the local registry component are delegated to the remote registry component which is implemented as CORBA object and reachable via the CORBA naming service. All calls which are received by the remote registry component are forwarded to all running //SOF// processes.
Articles for SOF and Remote SOF can be found here:
http://www.codeproject.com/KB/library/SOF_.aspx
http://www.codeproject.com/KB/library/Remote_SOF.aspx
!!!Supported Platforms
Basically //SOF// is implemented platform independent and can be compiled and run for all possible platforms where a standard C++ compiler is available.
[[SCons|http://www.scons.org/]] is the command line build tool which allows building //SOF// for different platforms. Since //SOF// was implemented on a Windows PC with Visual Studio C++ 2008 there are also Visual Studio project files available for building the framework.
!!!Building SOF
!!!!Windows
!!!!!Visual Studio
Start the Visual Studio, go to the //sof/impl// directory and load the //sof.sln// (Microsoft Visual Studio Solution) file. Afterwards the build process can be started with Visual Studio.
!!!!!~SCons
* Follow the instructions at [[SCons user guide page|http://www.scons.org/]] for installing Python and ~SCons
* Open a command shell on Windows and set the path and environment variables for command line builds. This can be done by changing to the //\bin// subdirectory of your Visual C++ installation and running //vcvars32.bat// (or just opening a Visual Studio command shell).
* Change to the //SOF// root directory and type
** //"""scons --sconstruct=sof.sconstruct mode=release"""// for creating a release build
** //"""scons --sconstruct=sof.sconstruct mode=debug"""// for creating a debug build
!!!!Other platforms
!!!!!~SCons
The build process for other platforms is not tested yet. Please try following steps:
* Follow the instructions at [[SCons user guide page|http://www.scons.org/]] for installing Python and ~SCons at your current platform
* Set the path and environment variables for command line builds.
* Change to the //SOF// root directory and type
** //"""scons --sconstruct=sof.sconstruct mode=release"""// for creating a release build
** //"""scons --sconstruct=sof.sconstruct mode=debug"""// for creating a debug build
!!!Using SOF
After building SOF the //bin// directory of the //impl// directory contains a library called //sof.lib// which can be linked.
!!Building 3rd party CORBA library MICO
!!!Windows
//Remote SOF// uses MICO (=CORBA implementation) as third party library for implementing remote accessible services and service listeners. Before //Remote SOF// can be build, the MICO libraries must be build.
Execute following steps for building MICO version 2.3.13 on Windows with Visual C++.
* Download the MICO distribution (http://www.mico.org/mico-2.3.13.zip)
* Extract the zip file
* Start the Visual Studio command shell
* Change into MICO main directory
* Enter 'nmake /f Makefile.win32'
Afterwards MICO is build as a ''dynamic'' library. Binaries (executables, ~DLLs, ~LIBs) are placed into 'mico\win32-bin' and 'mico\win32-bin\lib' directory.
!!!Other platforms
For building other MICO versions or building on different platforms please read the MICO documentation.
!!Building //Remote SOF//
!!!Windows
!!!!Visual Studio
* Extract the zip file of the //SOF// distribution into a directory
* Copy the CORBA binaries of the MICO distribution into the //Remote SOF// directory
** 'idl.exe' and 'nsd.exe' to 'sof\remote\corba\bin'
** The content of the MICO 'include' directory into 'sof\remote\corba\include'
** The libraries 'idl2313.lib', 'mico2313.lib', 'micocoss2313.lib', 'pthreadVC2.lib', 'idl2313.dll', 'mico2313.dll', 'micocoss2313.dll', 'pthreadVC2.dll' into 'sof\remote\corba\libs'
* Load file called 'sof_remote.sln' in directory 'sof\remote\impl' with Visual Studio
* Build all projects
!!!!~SCons
* Extract the zip file of the //SOF// distribution into a directory
* Copy the CORBA binaries of the MICO distribution into the //Remote SOF// directory
** 'idl.exe' and 'nsd.exe' to 'sof\remote\corba\bin'
** The content of the MICO 'include' directory into 'sof\remote\corba\include'
** The libraries 'idl2313.lib', 'mico2313.lib', 'micocoss2313.lib', 'pthreadVC2.lib', 'idl2313.dll', 'mico2313.dll', 'micocoss2313.dll', 'pthreadVC2.dll' into 'sof\remote\corba\libs'
* Follow the instructions at [[SCons user guide page|http://www.scons.org/]] for installing Python and ~SCons on Windows
* Open a command shell on Windows and set the path and environment variables for command line builds. This can be done by changing to the //\bin// subdirectory of your Visual C++ installation and running //vcvars32.bat// (or just opening a Visual Studio command shell).
* Change to the //SOF// root directory and type
** //"""scons --sconstruct=sof_remote.sconstruct mode=release"""// for creating a release build
** //"""scons --sconstruct=sof_remote.sconstruct mode=debug"""// for creating a debug build
!!!Other platforms
The build process for other platforms is not tested yet. Please try following steps:
* Extract the zip file of the //SOF// distribution into a directory
* Copy the CORBA binaries of the MICO distribution into the //Remote SOF// directory
** 'idl' executable and 'nsd' executable to 'sof\remote\corba\bin'
** The content of the MICO 'include' directory into 'sof\remote\corba\include'
** The libraries 'idl2313', 'mico2313', 'micocoss2313', 'pthreadVC2' into 'sof\remote\corba\libs'
* Follow the instructions at [[SCons user guide page|http://www.scons.org/]] for installing Python and ~SCons at your current platform
* Set the path and environment variables for command line builds.
* Change to the //SOF// root directory and type
** //"""scons --sconstruct=sof_remote.sconstruct mode=release"""// for creating a release build
** //"""scons --sconstruct=sof_remote.sconstruct mode=debug"""// for creating a debug build
!!Using //Remote SOF//
After building //Remote SOF// the bin directory of the impl directory contains a library called 'sof_remote' which can be linked.
''Windows note:'' Due to the fact that MICO is build dynamically (no static MICO libraries) the PATH variable of the Windows console has to be extended before the executables using the //Remote SOF// library can be executed:
PATH=%PATH%;%SOFHOME%\remote\corba\libs\win32-bin
This makes sure that the necessary MICO ~DLLs are found during runtime.
!!Other platforms
To be done.
This chapter describes how bundles are created, started and stopped by the framework.
![[Instantiation of the Bundle Activator]]
![[Starting SOF]]
![[Starting Bundles]]
![[Stopping Bundles]]
The SOF console provides a text based user interface for starting and stopping bundles. The console can be started by calling {{{sof_console.exe}}} which is located in directory '//sof\console\bin//'. See [[Starting SOF]] for further information.
[img[http://farm4.static.flickr.com/3251/2678806149_914f03de0d_o.gif]]
If you enter 'help' the console prints out all possible commands which can be executed within the console application. Following commands are available:
''Commands for creating and starting bundles''
* //stb//:
** Starts a local bundle which means that the bundle activator class is linked to the console application.
** Parameters:
*** The name of the bundle.
*** The name of the bundle activator class.
** Example: {{{stb test_bundle TestBundleActivator}}}
* //stbdll//:
** Starts a bundle from DLL.
** Parameters:
*** The name of the bundle.
*** The name of the bundle activator class.
*** The directory where the DLL is located.
*** The name of the DLL.
** Example: {{{stbdll test_bundle TestBundleActivator c:/libs test_bundle.dll}}}
* //stbfile//:
** Starts bundles which are specified in a configuration file.
** Example: {{{stbfile c:/test/test_config_file.sof}}}
** Each line of the configuration file represents the bundle configuration of one bundle.
*** Configuration line for a local bundle: <bundle_name>,<bundle_activator_class_name>
*** Configuration line for a bundle loaded from a DLL: <bunde_name>,<bundle_activator_class_name>,<dll_directory>,<dll_name>
''Commands for stopping bundles''
* //spb//:
** Stops a bundle.
** Parameters:
*** The name of the bundle.
** Example: {{{spb test_bundle}}}
* //spab//:
** Stops all active bundles.
''Commands for getting bundle information''
* //dbi//:
** Dumps all relevant information of the specified bundle.
** Parameters:
*** The name of the bundle.
** Example: {{{dbi test_bundle}}}
* //dab//:
** Dumps all relevant information of all bundles.
** Parameters:
*** None
** Example: {{{dab}}}
!The ''S''ervice ''O''riented ''F''ramework (SOF)
The SOF supports developing modular software which consists of components (bundles). Each component can register services which can be used by other bundles.
!![[Building]]
!![[Implementing a bundle]]
!![[Bundle Lifecycle]]
!![[Implementing a service]]
!![[Registering services]]
!![[Tracking services]]
!![[Building|Building Remote SOF]]
!![[Using Remote SOF]]
Following stable builds are available. For downloading the software please click [[here|http://sourcefoge.net/project/showfiles.php?group_id=217435]].
* sof_XXX (The next version)
** Features:
*** Unit tests for //Remote SOF// are available now. Please look at 'sof/remote/test' directory.
** Bugfixes:
*** Problems found with [[CppCheck|http://sourceforge.net/projects/cppcheck/]] fixed.
*** Memory leak of ~RemoteServiceInfo objects [[ID 2970487|https://sourceforge.net/tracker/?func=detail&aid=2970487&group_id=217435&atid=1040234]]
*** Remote registry not synchronizable [[ID 2952968|https://sourceforge.net/tracker/?func=detail&aid=2952968&group_id=217435&atid=1040234]]
*** Remote registry not exception safe [[ID 2928038|https://sourceforge.net/tracker/?func=detail&aid=2928038&group_id=217435&atid=1040234]]
*** Logger implementation not thread safe [[ID 2936130|https://sourceforge.net/tracker/?func=detail&aid=2936130&group_id=217435&atid=1040234]]
*** ~ServiceTracker not exception safe [[ID 2927343|https://sourceforge.net/tracker/?func=detail&aid=2927343&group_id=217435&atid=1040234]]
*** GCC compile error (enum) [[ID 2936129|https://sourceforge.net/tracker/?func=detail&aid=2936129&group_id=217435&atid=1040234]]
*** Concrete naming service address has to be removed [[ID 2940740|https://sourceforge.net/tracker/?func=detail&aid=2940740&group_id=217435&atid=1040234]]
*** Compile Errors in ~VC2008 fixed (thanks to Philipp Kursawe) [[ID 3000083|http://sourceforge.net/tracker/?func=detail&aid=3000083&group_id=217435&atid=1040234]]
* ''Last STABLE version: sof_1.0_9120 (includes SOF and Remote SOF'')
** Release notes:
*** Features:
**** Platform independent build tool for building [[SOF|Building]] and [[Remote SOF|Building Remote SOF]]
**** The //Remote SOF// console application (sof_remote_console) requires now a process name ('-proc_name:<process_name>') which is defined as program argument of the console application. The process name is necessary for identifying the //Remote SOF// processes in the new diagnosis and administration UI.
**** [[Diagnosis & Administration UI|SofAdminUI]]
*** Thank you very much for the patches:
**** Provided by Eugene Burov:
***** 'null reference exception - [[ID: 2909759|http://sourceforge.net/tracker/index.php?func=detail&aid=2909759&group_id=217435&atid=1040234]]'
**** Provided by Jan Hölscher:
***** 'simple Patch File to build this project on Linux - [[ID: 2904953|http://sourceforge.net/tracker/index.php?func=detail&aid=2904953&group_id=217435&atid=1040236]]'
*** Bugfixes:
**** The instance map of class {{{ObjectCreator}}} has to be checked for null before using it [[2808884|http://sourceforge.net/tracker/?func=detail&aid=2808884&group_id=217435&atid=1040234]]
**** Services and service listeners were not deregistered correctly [[2818458|http://sourceforge.net/tracker/?func=detail&aid=2818458&group_id=217435&atid=1040234]]
**** Services which are in use are not listed in Remote SOF console [[2818461|http://sourceforge.net/tracker/?func=detail&aid=2818461&group_id=217435&atid=1040234]]
**** Services are listed twice as 'used' services in Remote SOF console [[2821783|http://sourceforge.net/tracker/?func=detail&aid=2821783&group_id=217435&atid=1040234]]
* ''sof_9070 (includes SOF and Remote SOF)''
** Release notes:
*** New features:
**** SOF supports distributed bundles now. That means services and service listeners can be called across several processes whereas CORBA is used as communication layer.
*** Changes:
**** Implementation of Remote SOF
**** {{{BundleInfoBase}}} as base class for {{{RemoteBundleInfo}}} and {{{BundleInfo}}} class implemented
**** Using the {{{IMultiplier}}} interface as service interface for SOF examples
**** The implementationof {{{IBundleContextIImpl#registerService}}} was moved completely to the {{{IRegistryImpl}}} class.
**** The creation of {{{ServiceInfo}}} and {{{ServiceListenerInfo}}} object was moved to the {{{IBundleContextImpl}}} class.
**** Implementation of {{{toString}}} method for {{{ServiceEvent}}} and {{{ServiceReference}}} class
* ''sof_8070''
** Release notes:
*** New features:
**** The {{{addingService}}} method of the {{{IServiceTrackerCustomizer}}} interface has been extended by a boolean return value. By this the service tracker can accept or refuse found services. If the service tracker accepts a service by returning 'true', the service is regarded as a 'used service', otherwise not.
**** The threading and creation policies have been introduced. This allows to make the way of loading bundles and the threading behaviour of the framework configurable.
**** An 'examples' project has been added which gives examples for implementing bundles, registering and tracking services.
*** Bugfixes:
**** Registering the administration service [[2002904|http://sourceforge.net/tracker/index.php?func=detail&aid=2002904&group_id=217435&atid=1040234]]
**** Bugfix for service listener notification problem [[1997433|http://sourceforge.net/tracker/index.php?func=detail&aid=1997433&group_id=217435&atid=1040234]]
* ''sof_8050''
** Release notes:
*** Supported features:
**** Implementing bundles
**** Starting and stopping bundles via //SOF// console
**** Implementing services
**** Registering, unregistering and tracking services
*** Open issues:
**** Only single threaded solution available
**** Hard coded windows solution for starting bundles from ~DLLs.
Please look at SOF's [[download|Download]] section where you can find further information. There is no extra download package for the //Remote SOF// software. //SOF// and //Remote SOF// are packed together in one zip file.
For implementing a bundle the {{{sof::framework::IBundleActivator}}} interface has to be implemented:
{{{
class IBundleActivator
{
public:
virtual void start( IBundleContext::ConstPtr context ) = 0;
virtual void stop( IBundleContext::ConstPtr context ) = 0;
};
}}}
In the {{{start( IBundleContext::ConstPtr )}}} method you have to do all the things which are necessary for running the application code. The passed bundle context object allows you to interact with the SOF framework, like registering or tracking services (see [[Registering and tracking services]]).
When {{{stop( IBundleContext::ConstPtr )}}} is called all the application relevant resources which were allocated by the bundle must be cleaned. The {{{start}}} and {{{stop}}} methods are called by the framework. When {{{stop}}} method is called, the bundle context pointer need not be deleted by the bundle but is deleted by the SOF framework.
The bundle activator need not be instantiated by the application developer but is created also by the framework (see [[Bundle Lifecycle]]). For this the developer of every bundle has to make known the bundle activator class with the framework. This is done by using the {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro defined in the {{{sof/instantiation/ObjectCreator.h}}} header file:
{{{
#include "BundleActivatorImpl.h"
#include "sof/instantiation/ObjectCreator.h"
using namespace sof::framework;
using namespace sof::instantiation;
void BundleActivatorImpl::start( IBundleContext::ConstPtr ctxt )
{
}
BundleActivatorImpl::~BundleActivatorImpl()
{
}
void BundleActivatorImpl::stop( IBundleContext::ConstPtr context )
{
}
REGISTER_BUNDLE_ACTIVATOR_CLASS( "BundleActivatorImpl", BundleActivatorImpl)
}}}
The {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro expects three parameters:
* The name of the activator class (can be any name, but normally the name of the bundle activator class is chosen).
* The type of the specific bundle activator class which implements the {{{IBundleActivator}}} interface.
!Implementing a Local Bundle
Local means, that the class which implements the {{{IBundleActivator}}} interface is linked to the executable within the framework runs. The bundle need not to be created by loading a DLL (=''D''ynamic ''L''ink ''L''ibrary). For implementing a local bundle you have to do the things as described above (implementing the {{{IBundleActivator}}} interface and registering the activator class). Afterwards the bundle classes have to be linked with the main class which starts the framework.
!Implementing a DLL Bundle
Loading bundles from a dynamic link library is dependent on the used operating system.
For implementing a bundle which is loaded from a Windows DLL following operations have to be done:
* A {{{DllMain}}} method has to be implemented (instead of implementing a common {{{main}}} method for executable code)
* The DLL code must provide the method {{{ITest* createObject( const string &className )}}}. This method uses the {{{ObjectCreator}}} class (provided by //SOF//) for creating the {{{IBundleActivator}}} object by name.
* A bundle activator class has to be implemented.
* The bundle classes (the bundle activator, the class containing the {{{DllMain}}} etc.) must be build as DLL with the IDE.
{{{
#include <windows.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include "dll_test.h"
#include "ITest.h"
#include "sof/instantiation/ObjectCreator.h"
#include "sof/framework/IBundleActivator.h"
#include "sof/util/logging/LoggerFactory.h"
#include "sof/util/logging/Logger.h"
#define DLL extern "C" __declspec(dllexport)
using namespace std;
using namespace sof::instantiation;
using namespace sof::framework;
using namespace sof::util::logging;
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if(ul_reason_for_call==DLL_THREAD_ATTACH)
{
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[dll_test1#DllMain] Called, dll thread attach." );
} else if(ul_reason_for_call==DLL_THREAD_DETACH)
{
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[dll_test1#DllMain] Called, dll thread detach." );
} else if(ul_reason_for_call==DLL_PROCESS_ATTACH)
{
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[dll_test1#DllMain] Called, dll process attach." );
} else if(ul_reason_for_call==DLL_PROCESS_DETACH)
{
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[dll_test1#DllMain] Called, dll process detach." );
}
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[dll_test1#DllMain] Left." );
return TRUE;
}
DLL ITest* createObject( const string &className )
{
ObjectCreator<IBundleActivator> OC_BUNDLE_ACTIVATOR;
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[dll_test1#createObject] Loading instance of class '%1'.", className );
return OC_BUNDLE_ACTIVATOR.createObject( className );
}
}}}
A service is registered with the framework by a bundle and implements a well known interface. The service can be tracked and then called by other bundles. Each bundle can register zero or several services.
!The {{{IService}}} interface
Every service has to implement the {{{IService}}} interface which is defined in the {{{sof::framework}}} namespace. The {{{IService}}} interface does not provide any methods. It is only a marker interface which declares a class as a service.
!Example:
''The service interface:''
{{{
#ifndef I_MY_SERVICE_H
#define I_MY_SERVICE_H
#include "sof/framework/IService.h"
using namespace sof::framework;
class IMyService: public IService
{
public:
virtual int getValue() = 0;
};
#endif
}}}
The user defined service interface {{{IMyService}}} which inherits from the service interface of the framework ({{{sof::framework::IService}}}) provides here only one method called {{{int getValue()}}}.
''The implementation:''
The following code snippets show the implementation of the user defined service interface.
Header file:
{{{
#ifndef I_MY_SERVICE_IMPL_H
#define I_MY_SERVICE_IMPL_H
#include "IMyService.h"
using namespace sof::framework;
class IMyServiceImpl: public IMyService
{
public:
int getValue();
};
#endif
}}}
CPP file:
{{{
#include "IMyServiceImpl.h"
int IMyServiceImpl::getValue()
{
return 42;
}
}}}
Now instances of class {{{IMyServiceImpl}}} can be registered with the framework. See chapter [[Registering services]]
The intention of the framework is to avoid that the application developer is responsible for the lifecycle of his implemented bundles. That means the creation, starting and stopping of the software bundles must be done by the framework:
[img[http://farm3.static.flickr.com/2183/2326314896_c15355177a_o.gif]]
The only thing the developer must do is [[implementing the bundle|Implementing a bundle]] and specifiying (by configuration file for example) which bundles shall be created and started. Consequently the framework must be able to create instances of type {{{sof::framework::IBundleActivator}}} by name. Ok, you have to do a little more than only implementing the {{{IBundleActivator}}} interface. The name of the class which implements the {{{IBundleActivator}}} interface has to be registered with the framework (see usage of {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro in following code example):
{{{
#include "TestBundleActivator.h"
#include "sof/instantiation/ObjectCreator.h"
#include "sof/util/logging/Logger.h"
#include "sof/util/logging/LoggerFactory.h"
using namespace std;
using namespace sof::instantiation;
using namespace sof::framework;
void TestBundleActivator::start( IBundleContext::ConstPtr context )
{
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[TestBundleActivator#start] Called."
}
TestBundleActivator::~TestBundleActivator()
{
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[TestBundleActivator#destructor] Called." );
}
void TestBundleActivator::stop( IBundleContext::ConstPtr context )
{
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[TestBundleActivator#stop] Called." );
}
REGISTER_CLASS("TestBundleActivator",IBundleActivator,TestBundleActivator)
}}}
The {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro is defined in the header file named {{{sof/instantiation/ObjectCreator.h}}} and asks for two parameters:
* The name of the class which is used for instantiation
* The name of the class which implements the {{{IBundleActivator}}} interface
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
major: 1, minor: 1, revision: 0,
date: new Date("mar 17, 2007"),
source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};
if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};
bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){
url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
}
return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
[img[netzwerk|http://farm3.static.flickr.com/2271/2249573201_120174d813_o.png]]
[[News]]
[[About]]
[[Articles]]
[[Project Structure]]
[[Documentation|Documentation]]
[[API|API]]
[[Download|Download]]
[[SOF Console|Console]]
[[Remote SOF]]
[[Open Issues]]
''December 21, 2009''
New version ''SOF 1.0'' (including the frameworks SOF and Remote SOF) available. Please look [[here|Download]] for the release notes.
Merry Christmas!
''July 8, 2009''
Remote SOF is available. It represents an extension for SOF and supports calling distributed bundles by using CORBA as communication layer.
* Directly ask the bundle context for service references (instead of being notified)
* Improving error robustness
* More features for ~SofAdminUI
** Starting and stopping bundles
** Code generation of infrastructure code (registering listeners, tracking services etc.)
* Unit tests for Remote SOF
* Adding dependencies between bundles
** Examples:
*** Bundle A requires version 2.0 of bundle B
*** Bundle A requires version 1.2 of service B
[<img[netzwerk|http://farm4.static.flickr.com/3202/2679653624_fc6aed3ace_o.gif]]
''The SOF software consists of the four projects:''
* //impl//: The SOF kernel
* //test//: Unit tests for testing the framework
* //examples//: Examples of implemented bundles (which register/track services)
* //console//: The SOF console which provides a text based user interface for starting and stopping bundles, dump bundle infos etc.
''Each project can consist of following sub directories:''
* //src//: Contains header and source files
* //build//: Used for building the project
* //bin//: Contains the output of the build process, e.g. an '.exe' of '.dll' file
The 'doc' directory contains the SOF documentation including the API documentation and the website content as local file. For implemented unit tests an extern unit test library is necessary called '~CppUniteLite' which is located in the 'extern directory'.
[<img[remote_sof_project_structure|http://farm4.static.flickr.com/3573/3551576055_569cbd97ca_o.gif]]
''The //Remote SOF// software consists of the three projects:''
* //impl//: The //Remote SOF kernel// which extends the //SOF// kernel
* //examples//: Examples of implemented bundles (which register/track services)
* //registry//: The registry which delegates the registering/deregistering of services and service listeners to all //SOF// processes.
''Each project can consist of following sub directories:''
* //src//: Contains header and source files
* //build//: Used for building the project
* //bin//: Contains the output of the build process, e.g. an '.exe' of '.dll' file
The 'corba' directory contains following sub directories:
* //bin//: Contains executable CORBA MICO files (e.g. for running the CORBA naming service, running the IDL compiler etc.).
* //include//: Contains the CORBA MICO header files.
* //libs//: Contains the CORBA MICO libraries.
[<img[netzwerk|http://farm3.static.flickr.com/2252/2266693776_2d4c510ec1_o.gif]]
''The SOF software consists of the three projects:''
* //impl//: The SOF kernel
* //test//: Unit tests for testing the framework
* //console//: The SOF console which provides a text based user interface for starting and stopping bundles, dump bundle infos etc.
''Each project has following sub directories:''
* //src//: Contains header and source files
* //build//: Used for building the project
* //bin//: Contains the output of the build process, e.g. an '.exe' of '.dll' file
The 'doc' directory contains the SOF documentation including the API documentation and the website content as local file. For implemented unit tests an extern unit test library is necessary called 'CppUniteLite' which is located in the 'extern directory'.
Service objects can be registered during the total lifetime of a bundle. In the following example a service object is registered by the {{{start( IBundleContext )}}} method. For registering a service the {{{registerService}}} method of the bundle context object has to be called.
The {{{registerService}}} method expects three parameters:
* The arbitrary service name
* The service object (which implements the {{{IService}}} interface)
* The {{{Properties}}} object which contains user defined additional information regarding to the service object.
{{{
...
void BundleActivator::start( IBundleContext::ConstPtr context )
{
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[BundleActivator#start] Called." );
Properties props;
props.put( "ID", "4711 );
IServiceRegistration* serviceReg = context->registerService( "ServiceA", new IMyServiceImpl(), props );
}
...
}}}
After a service is registered the framework notifies all service listeners (which were registered for the specified service name, here: "~ServiceA") about the registered service object. See chapter [[Tracking services]].
''Note:''
The {{{registerService}}} method returns a pointer to a {{{IServiceRegistration}}} object which provides only one method called {{{unregister}}}. That means the registration object allows to unregister the service object with the framework (if it is no longer needed) and the framework notifies all other bundles which are using this service via the service listeners.
The following diagram shows an use case where one bundle registers a service object and the other bundles (which track this service) are notified via the service listeners. This diagram shows the case when the service listeners are registered after the service object was registered. It could also happen that the service object is registered after the service listener objects were registered. In this case the service listeners would be notified after the registration of the service object.
[img[http://farm3.static.flickr.com/2362/2437534147_4e84b3db6b_o.jpg]]
[[About|About Remote SOF]]
[[Project Structure|Project Structure - Remote SOF]]
[[Documentation|Documentation - Remote SOF]]
[[API|API Remote SOF]]
[[Download|Download Remote SOF]]
[[SOF Console|Remote SOF console]]
[[Diagnosis & Administration UI|SofAdminUI]]
Service Oriented Framework
The //~SofAdminUI// represents a diagnosis an administration tool for //Remote SOF//. The first version of the tool does not implement any administration features yet but it allows to display the bundle data of the running bundles.
At [[Sourceforge|http://sourceforge.net/projects/sof/files/]] you'll find the latest binaries for several platforms. Please choose the right one and unzip the archive file into a directory. Afterwards run the 'eclipse' executable which you find in the 'eclipse' directory of the unzipped distribution. The tool is started and looks like as follows:
[img[SofAdminUI|http://farm5.static.flickr.com/4010/4202818162_6e800c7d6f_o.gif]]
The UI consists of two parts, the process view on the left side and the bundle data view on the right side. The process view lists all running //Remote SOF// processes (here 'ernie' and 'bert'). The process names here are consistent with the process names which are used for the //Remote SOF// console application. The view can be updated maybe after running further //Remote SOF// processes by pressing the 'Update View' button. Everytime you press the update button the ~SofAdminUI connects the CORBA naming service and reads all registered //Remote SOF// processes. The UI uses 'localhost:5000' as default address of the CORBA naming service. For the case you started the CORBA naming service on a different address and port, it is possible to define the address for the UI. For this you have to pass a program argument to its executable.
''Example:''
//eclipse.exe -~ORBInitRef.~NameService=corbaloc::<ip-address>:<port-number>/~NameService//
After choosing a process in the process view the bundle data view displays all running bundles of the selected process in the 'Bundle Names' list. If you click a bundle in the list, all registered services, used services and registered service listeners are listed in the fields next to the bundle list.
!By program at framework startup
The {{{Launcher}}} class offers following method for starting bundles:
{{{
void start( vector<BundleConfiguration> &configuration );
}}}
The parameter which has to be passed to the method call represents a vector of {{{sof::config::BundleConfiguration}}} objects. Each {{{BundleConfiguration}}} object defines the configuration of one bundle.
''Example:''
{{{
BundleConfiguration bundleConf( "MyBundle", "MyBundleActivator", "c:/temp", "mybundle.dll" );
}}}
The {{{BundleConfiguration}}} constructor requires following parameters:
* The name of the bundle (e.g. "~MyBundle" )
* The name of the activator class (e.g. "~MyBundleActivator") which must be defined in the implementation class by using the {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro .
* The following parameters are optional and only necessary for configuring an external bundle (which is loaded from a library):
** The path to the directory where the bundle library is located (e.g. "c:/temp")
** The name of the bundle library (e.g. "mybundle.dll")
In the following example the launcher starts two bundles, one local and one external bundle:
{{{
#include <iostream>
#include "sof/framework/Launcher.h"
#include "sof/framework/Global.h"
#include "sof/config/BundleConfiguration.h"
#include "sof/instantiation/win/WinDllCreator.h"
#include "sof/util/threading/SingleThreaded.h"
using namespace std;
using namespace sof::framework;
using namespace sof::instantiation::win;
using namespace sof::config;
using namespace sof::util::threading;
int main(int argc, char* argv[])
{
// Framework launcher class
Launcher<SingleThreaded,WinDllCreator> launcher;
// Sets the log level of the framework
launcher.setLogLevel( Logger::LogLevel::DEBUG );
// Creating the bundle configuration
BundleConfiguration bundleConf1( "bundle1", "BundleActivator2", ".", "sof_TestDll2.dll" );
BundleConfiguration bundleConf2( "bundle2", "TestBundleActivator" );
vector<BundleConfiguration> bundleConfVec;
bundleConfVec.push_back( bundleConf1 );
bundleConfVec.push_back( bundleConf2 );
// Starts the bundles which are configured by BundleConfiguration vector
launcher.start( bundleConfVec );
// Starts the administration bundle which implements the SOF console
launcher.startAdministrationBundle();
return 0;
}
}}}
!By program via administration interface
//SOF// offers an administration interface which can be tracked and called. The administration interface or bundle can be started as follows:
{{{
laucher.startAdministrationBundle();
}}}
The administration interface is defined in class {{{sof::services::admin::IAdministrationService}}} and can be tracked by using the name 'sof::services::admin::~IAdministrationService'. The provided methods for starting bundles are:
{{{
class IAdministrationService
{
public:
virtual void startBundleFromDLL( const string& bundleName, const string& className, const string& libPath, const string& libName ) = 0;
virtual void startBundle( const string& bundleName, const string& className ) = 0;
virtual void startBundlesFromConfigFile( const string& configFile ) = 0;
};
}}}
Method parameters:
* {{{startBundle}}}: Starts a local bundle.
** //bundleName//: The name of the bundle which is started.
** //className//: The name of the bundle activator class.
* {{{startBundleFromDLL}}}: Starts a bundle from a dynamic link library.
** //bundleName//: The name of the bundle which is started.
** //className//: The name of the bundle activator class.
** //libPath//: The path to the directory where the library file is located (e.g. 'c:/bundles').
** //libName//: The name of the library which contains the bundle classes.
* {{{startBundlesFromConfigFile}}}: Starts a bundle which is configured in a file.
** //configFile//: The configuration file which specifies the bundle configuration data.
*** The configuration file can contain several entries whereas one entry consists of:
**** for external bundles (loaded from DLL): bundle_name,bundle_activator_class_name,library_path,library_name
**** for local bundles: bundle_name,bundle_activator_class_name
!By //SOF// console
It is also possible to start bundles via console after //SOF// was started. For starting the framework please look [[here|Starting SOF]]. When framework is up and the //SOF// console is ready for processing commands, following commands for starting bundles are available:
* stb (= starting bundle)
* stbdll (= starting bundle from DLL)
The exact notation of the commands (including passing parameters) you can find [[here|Console]]
Before bundles can be created and started the SOF framework has to be started. For this you have to create a class with following {{{main}}} method:
{{{
#include <iostream>
#include "sof/framework/Launcher.h"
#include "sof/framework/Global.h"
#ifdef WIN
#include "sof/instantiation/win/WinDllCreator.h"
#endif
#include "sof/util/threading/SingleThreaded.h"
using namespace std;
using namespace sof::framework;
#ifdef WIN
using namespace sof::instantiation::win;
#endif
using namespace sof::util::threading;
int main(int argc, char* argv[])
{
// Framework launcher class
#ifdef WIN
Launcher<SingleThreaded,WinDllCreator> launcher;
#else
Launcher<SingleThreaded,NullCreator> launcher;
#endif
// Sets the log level of the framework
launcher.setLogLevel( Logger::LogLevel::DEBUG );
// Starts the administration bundle which implements the SOF console
launcher.startAdministrationBundle();
return 0;
}
}}}
Such a class is also provided by the SOF framework itself. Please look into class {{{sof_console.cpp}}} in source folder of //console// project. The {{{Launcher}}} is a template based class and requires the definition of two policies:
!! Threading policy
By implementing the threading policy it can be defined whether the {{{Launcher}}} class is able to act in a multi-threaded environment or supports only a single-threaded environment. The //SOF// framework provides a default implementation of the threading policy called {{{sof::util::threading::SingleThreaded}}} which demands that framework calls (registering and unregistering listeners, services etc.) have to be done in a single thread and the calls don't have to be synchronized.
If the user of the //SOF// framework wants to develop a multithreaded software which includes registering services and service listeners concurrently, the user ought to implement the threading policy in order to avoid race conditions due to concurrent modifications in the {{{sof::framework::IRegistry}}} class.
!! Creation policy
The creation policy defines how bundle activator instances can be created from a DLL (=''D''ynamic ''L''ink ''L''ibrary). Standard C++ provides no support for loading dynamic link libraries. By implementing the creation policy the user of the //SOF// framework is able to adapt the DLL loading mechanism for different platforms.
//SOF// currently provides only an implementation of the creation policy for the windows platform (see {{{sof::instantiation::win::WinDllCreator}}}).
!! Startup
After starting your program (or the //sof_console.exe// of the //console\bin// directory), you see following output:
[img[http://farm3.static.flickr.com/2295/2323942752_44bd18e0d5_o.gif]]
The //SOF// console, which provides a text based user interface, is started and waits for user input.
If you are not interested in log messages of the framework, the log level of the framework can be changed or deactivated as follows:
{{{
#include <iostream>
#include "sof/framework/Launcher.h"
#include "sof/framework/Global.h"
#ifdef WIN
#include "sof/instantiation/win/WinDllCreator.h"
#endif
#include "sof/instantiation/NullCreator.h"
#include "sof/util/threading/SingleThreaded.h"
using namespace std;
using namespace sof::framework;
using namespace sof::util::threading;
#ifdef WIN
using namespace sof::instantiation::win;
#endif
int main(int argc, char* argv[])
{
Logger::LogLevel logLevel = Logger::LogLevel::DEBUG;
for ( int i=0; i<argc; i++ )
{
string arg(argv[i]);
if ( arg == "-nolog" )
{
logLevel = Logger::LogLevel::NOLOG;
}
else if ( arg == "-errorlog" )
{
logLevel = Logger::LogLevel::ERROR_;
}
else if ( arg == "-debuglog" )
{
logLevel = Logger::LogLevel::DEBUG;
}
}
#ifdef WIN
Launcher<SingleThreaded,WinDllCreator> launcher;
#else
Launcher<SingleThreaded,NullCreator> launcher;
#endif
launcher.setLogLevel( logLevel );
launcher.startAdministrationBundle();
return 0;
}
}}}
For getting more information relating to the //SOF// console please click [[here|Console]].
!By //SOF// console
The //SOF// console provides following commands for stopping bundles:
* //spb//: Stops one bundle specified by name.
* //spab//: Stops all active bundles.
For precise explanation of the commands please look [[here|Console]]
!By administration interface
Tracking a service means that a bundle instructs the framework to watch over a registered or deregistered service. When the specified service is registered or deregistered the framework notifies the interested bundle about the registered or deregistered service.
For tracking a service the bundle has to create a {{{ServiceTracker}}} object. Tracking begins as soon as the {{{startTracking}}} method is called and ends when the {{{stopTracking}}} method is called. Only during the tracking is active the bundle is notified about lifetime changes of a service.
{{{
void BundleActivator::start( IBundleContext::ConstPtr context )
{
LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[BundleActivator#start] Called." );
this->tracker = new ServiceTracker( context, "ServiceA", this );
this->tracker->startTracking();
}
}}}
The constructor of the tracker object requires three parameters:
* The bundle context object which allows the tracker object to communicate with the framework
* The name of the service which is tracked
* An object of type {{{IServiceTrackerCustomizer}}} which is notified about lifetime changes of the service object.
/***
Contains the stuff you need to use Tiddlyspot
Note you must also have UploadPlugin installed
***/
//{{{
// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'sof';
// make it so you can by default see edit controls via http
config.options.chkHttpReadOnly = false;
window.readOnly = false; // make sure of it (for tw 2.2)
// disable autosave in d3
if (window.location.protocol != "file:")
config.options.chkGTDLazyAutoSave = false;
// tweak shadow tiddlers to add upload button, password entry box etc
with (config.shadowTiddlers) {
SiteUrl = 'http://'+config.tiddlyspotSiteId+'.tiddlyspot.com';
SideBarOptions = SideBarOptions.replace(/(<<saveChanges>>)/,"$1<<tiddler TspotSidebar>>");
OptionsPanel = OptionsPanel.replace(/^/,"<<tiddler TspotOptions>>");
DefaultTiddlers = DefaultTiddlers.replace(/^/,"[[WelcomeToTiddlyspot]] ");
MainMenu = MainMenu.replace(/^/,"[[WelcomeToTiddlyspot]] ");
}
// create some shadow tiddler content
merge(config.shadowTiddlers,{
'WelcomeToTiddlyspot':[
"This document is a ~TiddlyWiki from tiddlyspot.com. A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //What now?// @@ Before you can save any changes, you need to enter your password in the form below. Then configure privacy and other site settings at your [[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]] (your control panel username is //" + config.tiddlyspotSiteId + "//).",
"<<tiddler TspotControls>>",
"See also GettingStarted.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Working online// @@ You can edit this ~TiddlyWiki right now, and save your changes using the \"save to web\" button in the column on the right.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// @@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick. You can make changes and save them locally without being connected to the Internet. When you're ready to sync up again, just click \"upload\" and your ~TiddlyWiki will be saved back to tiddlyspot.com.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Help!// @@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]]. Also visit [[TiddlyWiki Guides|http://tiddlywikiguides.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help. If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// @@ We hope you like using your tiddlyspot.com site. Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions."
].join("\n"),
'TspotControls':[
"| tiddlyspot password:|<<option pasUploadPassword>>|",
"| site management:|<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . . " + config.tiddlyspotSiteId + ">>//(requires tiddlyspot password)//<<br>>[[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]], [[download (go offline)|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download]]|",
"| links:|[[tiddlyspot.com|http://tiddlyspot.com/]], [[FAQs|http://faq.tiddlyspot.com/]], [[announcements|http://announce.tiddlyspot.com/]], [[blog|http://tiddlyspot.com/blog/]], email [[support|mailto:support@tiddlyspot.com]] & [[feedback|mailto:feedback@tiddlyspot.com]], [[donate|http://tiddlyspot.com/?page=donate]]|"
].join("\n"),
'TspotSidebar':[
"<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . . " + config.tiddlyspotSiteId + ">><html><a href='http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download' class='button'>download</a></html>"
].join("\n"),
'TspotOptions':[
"tiddlyspot password:",
"<<option pasUploadPassword>>",
""
].join("\n")
});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 08/02/2010 06:31:56 | magr74 | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . | ok |
| 08/02/2010 06:38:27 | magr74 | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 11/02/2010 05:50:55 | magr74 | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 16/02/2010 20:41:57 | magr74 | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 16/02/2010 20:45:39 | magr74 | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 25/02/2010 06:21:06 | magr74 | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 15/03/2010 05:45:09 | magr74 | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 15/03/2010 05:47:48 | magr74 | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 07/04/2010 00:07:56 | magr74 | [[index.20100314.2148300000.html|http://sof.tiddlyspot.com/_sites/s/so/sof/sof/backup/index.20100314.2148300000.html]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 25/05/2010 06:04:50 | magr74 | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
major: 1, minor: 0, revision: 2,
date: new Date("Apr 19, 2007"),
source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
author: 'BidiX (BidiX (at) bidix (dot) info',
license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
coreVersion: '2.2.0 (Beta 5)'
};
config.macros.option.passwordCheckboxLabel = "Save this password on this computer";
config.macros.option.passwordInputType = "password"; // password | text
setStylesheet(".pasOptionInput {width: 11em;}\n","passwordInputTypeStyle");
merge(config.macros.option.types, {
'pas': {
elementType: "input",
valueField: "value",
eventName: "onkeyup",
className: "pasOptionInput",
typeValue: config.macros.option.passwordInputType,
create: function(place,type,opt,className,desc) {
// password field
config.macros.option.genericCreate(place,'pas',opt,className,desc);
// checkbox linked with this password "save this password on this computer"
config.macros.option.genericCreate(place,'chk','chk'+opt,className,desc);
// text savePasswordCheckboxLabel
place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));
},
onChange: config.macros.option.genericOnChange
}
});
merge(config.optionHandlers['chk'], {
get: function(name) {
// is there an option linked with this chk ?
var opt = name.substr(3);
if (config.options[opt])
saveOptionCookie(opt);
return config.options[name] ? "true" : "false";
}
});
merge(config.optionHandlers, {
'pas': {
get: function(name) {
if (config.options["chk"+name]) {
return encodeCookie(config.options[name].toString());
} else {
return "";
}
},
set: function(name,value) {config.options[name] = decodeCookie(value);}
}
});
// need to reload options to load passwordOptions
loadOptionsCookie();
/*
if (!config.options['pasPassword'])
config.options['pasPassword'] = '';
merge(config.optionsDesc,{
pasPassword: "Test password"
});
*/
//}}}
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.0|
|''Date:''|May 5, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (#3125)|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
major: 4, minor: 1, revision: 0,
date: new Date("May 5, 2007"),
source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
author: 'BidiX (BidiX (at) bidix (dot) info',
coreVersion: '2.2.0 (#3125)'
};
//
// Environment
//
if (!window.bidix) window.bidix = {}; // bidix namespace
bidix.debugMode = false; // true to activate both in Plugin and UploadService
//
// Upload Macro
//
config.macros.upload = {
// default values
defaultBackupDir: '', //no backup
defaultStoreScript: "store.php",
defaultToFilename: "index.html",
defaultUploadDir: ".",
authenticateUser: true // UploadService Authenticate User
};
config.macros.upload.label = {
promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
promptParamMacro: "Save and Upload this TiddlyWiki in %0",
saveLabel: "save to web",
saveToDisk: "save to disk",
uploadLabel: "upload"
};
config.macros.upload.messages = {
noStoreUrl: "No store URL in parmeters or options",
usernameOrPasswordMissing: "Username or password missing"
};
config.macros.upload.handler = function(place,macroName,params) {
if (readOnly)
return;
var label;
if (document.location.toString().substr(0,4) == "http")
label = this.label.saveLabel;
else
label = this.label.uploadLabel;
var prompt;
if (params[0]) {
prompt = this.label.promptParamMacro.toString().format([this.destFile(params[0],
(params[1] ? params[1]:bidix.basename(window.location.toString())), params[3])]);
} else {
prompt = this.label.promptOption;
}
createTiddlyButton(place, label, prompt, function() {config.macros.upload.action(params);}, null, null, this.accessKey);
};
config.macros.upload.action = function(params)
{
// for missing macro parameter set value from options
var storeUrl = params[0] ? params[0] : config.options.txtUploadStoreUrl;
var toFilename = params[1] ? params[1] : config.options.txtUploadFilename;
var backupDir = params[2] ? params[2] : config.options.txtUploadBackupDir;
var uploadDir = params[3] ? params[3] : config.options.txtUploadDir;
var username = params[4] ? params[4] : config.options.txtUploadUserName;
var password = config.options.pasUploadPassword; // for security reason no password as macro parameter
// for still missing parameter set default value
if ((!storeUrl) && (document.location.toString().substr(0,4) == "http"))
storeUrl = bidix.dirname(document.location.toString())+'/'+config.macros.upload.defaultStoreScript;
if (storeUrl.substr(0,4) != "http")
storeUrl = bidix.dirname(document.location.toString()) +'/'+ storeUrl;
if (!toFilename)
toFilename = bidix.basename(window.location.toString());
if (!toFilename)
toFilename = config.macros.upload.defaultToFilename;
if (!uploadDir)
uploadDir = config.macros.upload.defaultUploadDir;
if (!backupDir)
backupDir = config.macros.upload.defaultBackupDir;
// report error if still missing
if (!storeUrl) {
alert(config.macros.upload.messages.noStoreUrl);
clearMessage();
return false;
}
if (config.macros.upload.authenticateUser && (!username || !password)) {
alert(config.macros.upload.messages.usernameOrPasswordMissing);
clearMessage();
return false;
}
bidix.upload.uploadChanges(false,null,storeUrl, toFilename, uploadDir, backupDir, username, password);
return false;
};
config.macros.upload.destFile = function(storeUrl, toFilename, uploadDir)
{
if (!storeUrl)
return null;
var dest = bidix.dirname(storeUrl);
if (uploadDir && uploadDir != '.')
dest = dest + '/' + uploadDir;
dest = dest + '/' + toFilename;
return dest;
};
//
// uploadOptions Macro
//
config.macros.uploadOptions = {
handler: function(place,macroName,params) {
var wizard = new Wizard();
wizard.createWizard(place,this.wizardTitle);
wizard.addStep(this.step1Title,this.step1Html);
var markList = wizard.getElement("markList");
var listWrapper = document.createElement("div");
markList.parentNode.insertBefore(listWrapper,markList);
wizard.setValue("listWrapper",listWrapper);
this.refreshOptions(listWrapper,false);
var uploadCaption;
if (document.location.toString().substr(0,4) == "http")
uploadCaption = config.macros.upload.label.saveLabel;
else
uploadCaption = config.macros.upload.label.uploadLabel;
wizard.setButtons([
{caption: uploadCaption, tooltip: config.macros.upload.label.promptOption,
onClick: config.macros.upload.action},
{caption: this.cancelButton, tooltip: this.cancelButtonPrompt, onClick: this.onCancel}
]);
},
refreshOptions: function(listWrapper) {
var uploadOpts = [
"txtUploadUserName",
"pasUploadPassword",
"txtUploadStoreUrl",
"txtUploadDir",
"txtUploadFilename",
"txtUploadBackupDir",
"chkUploadLog",
"txtUploadLogMaxLine",
]
var opts = [];
for(i=0; i<uploadOpts.length; i++) {
var opt = {};
opts.push()
opt.option = "";
n = uploadOpts[i];
opt.name = n;
opt.lowlight = !config.optionsDesc[n];
opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
opts.push(opt);
}
var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
for(n=0; n<opts.length; n++) {
var type = opts[n].name.substr(0,3);
var h = config.macros.option.types[type];
if (h && h.create) {
h.create(opts[n].colElements['option'],type,opts[n].name,opts[n].name,"no");
}
}
},
onCancel: function(e)
{
backstage.switchTab(null);
return false;
},
wizardTitle: "Upload with options",
step1Title: "These options are saved in cookies in your browser",
step1Html: "<input type='hidden' name='markList'></input><br>",
cancelButton: "Cancel",
cancelButtonPrompt: "Cancel prompt",
listViewTemplate: {
columns: [
{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
{name: 'Option', field: 'option', title: "Option", type: 'String'},
{name: 'Name', field: 'name', title: "Name", type: 'String'}
],
rowClasses: [
{className: 'lowlight', field: 'lowlight'}
]}
}
//
// upload functions
//
if (!bidix.upload) bidix.upload = {};
if (!bidix.upload.messages) bidix.upload.messages = {
//from saving
invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
backupSaved: "Backup saved",
backupFailed: "Failed to upload backup file",
rssSaved: "RSS feed uploaded",
rssFailed: "Failed to upload RSS feed file",
emptySaved: "Empty template uploaded",
emptyFailed: "Failed to upload empty template file",
mainSaved: "Main TiddlyWiki file uploaded",
mainFailed: "Failed to upload main TiddlyWiki file. Your changes have not been saved",
//specific upload
loadOriginalHttpPostError: "Can't get original file",
aboutToSaveOnHttpPost: 'About to upload on %0 ...',
storePhpNotFound: "The store script '%0' was not found."
};
bidix.upload.uploadChanges = function(onlyIfDirty,tiddlers,storeUrl,toFilename,uploadDir,backupDir,username,password)
{
var callback = function(status,uploadParams,original,url,xhr) {
if (!status) {
displayMessage(bidix.upload.messages.loadOriginalHttpPostError);
return;
}
if (bidix.debugMode)
alert(original.substr(0,500)+"\n...");
// Locate the storeArea div's
var posDiv = locateStoreArea(original);
if((posDiv[0] == -1) || (posDiv[1] == -1)) {
alert(config.messages.invalidFileError.format([localPath]));
return;
}
bidix.upload.uploadRss(uploadParams,original,posDiv);
};
if(onlyIfDirty && !store.isDirty())
return;
clearMessage();
// save on localdisk ?
if (document.location.toString().substr(0,4) == "file") {
var path = document.location.toString();
var localPath = getLocalPath(path);
saveChanges();
}
// get original
var uploadParams = Array(storeUrl,toFilename,uploadDir,backupDir,username,password);
var originalPath = document.location.toString();
// If url is a directory : add index.html
if (originalPath.charAt(originalPath.length-1) == "/")
originalPath = originalPath + "index.html";
var dest = config.macros.upload.destFile(storeUrl,toFilename,uploadDir);
var log = new bidix.UploadLog();
log.startUpload(storeUrl, dest, uploadDir, backupDir);
displayMessage(bidix.upload.messages.aboutToSaveOnHttpPost.format([dest]));
if (bidix.debugMode)
alert("about to execute Http - GET on "+originalPath);
var r = doHttp("GET",originalPath,null,null,null,null,callback,uploadParams,null);
if (typeof r == "string")
displayMessage(r);
return r;
};
bidix.upload.uploadRss = function(uploadParams,original,posDiv)
{
var callback = function(status,params,responseText,url,xhr) {
if(status) {
var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
displayMessage(bidix.upload.messages.rssSaved,bidix.dirname(url)+'/'+destfile);
bidix.upload.uploadMain(params[0],params[1],params[2]);
} else {
displayMessage(bidix.upload.messages.rssFailed);
}
};
// do uploadRss
if(config.options.chkGenerateAnRssFeed) {
var rssPath = uploadParams[1].substr(0,uploadParams[1].lastIndexOf(".")) + ".xml";
var rssUploadParams = Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
bidix.upload.httpUpload(rssUploadParams,convertUnicodeToUTF8(generateRss()),callback,Array(uploadParams,original,posDiv));
} else {
bidix.upload.uploadMain(uploadParams,original,posDiv);
}
};
bidix.upload.uploadMain = function(uploadParams,original,posDiv)
{
var callback = function(status,params,responseText,url,xhr) {
var log = new bidix.UploadLog();
if(status) {
// if backupDir specified
if ((params[3]) && (responseText.indexOf("backupfile:") > -1)) {
var backupfile = responseText.substring(responseText.indexOf("backupfile:")+11,responseText.indexOf("\n", responseText.indexOf("backupfile:")));
displayMessage(bidix.upload.messages.backupSaved,bidix.dirname(url)+'/'+backupfile);
}
var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
displayMessage(bidix.upload.messages.mainSaved,bidix.dirname(url)+'/'+destfile);
store.setDirty(false);
log.endUpload("ok");
} else {
alert(bidix.upload.messages.mainFailed);
displayMessage(bidix.upload.messages.mainFailed);
log.endUpload("failed");
}
};
// do uploadMain
var revised = bidix.upload.updateOriginal(original,posDiv);
bidix.upload.httpUpload(uploadParams,revised,callback,uploadParams);
};
bidix.upload.httpUpload = function(uploadParams,data,callback,params)
{
var localCallback = function(status,params,responseText,url,xhr) {
url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
if (xhr.status == httpStatus.NotFound)
alert(bidix.upload.messages.storePhpNotFound.format([url]));
if ((bidix.debugMode) || (responseText.indexOf("Debug mode") >= 0 )) {
alert(responseText);
if (responseText.indexOf("Debug mode") >= 0 )
responseText = responseText.substring(responseText.indexOf("\n\n")+2);
} else if (responseText.charAt(0) != '0')
alert(responseText);
if (responseText.charAt(0) != '0')
status = null;
callback(status,params,responseText,url,xhr);
};
// do httpUpload
var boundary = "---------------------------"+"AaB03x";
var uploadFormName = "UploadPlugin";
// compose headers data
var sheader = "";
sheader += "--" + boundary + "\r\nContent-disposition: form-data; name=\"";
sheader += uploadFormName +"\"\r\n\r\n";
sheader += "backupDir="+uploadParams[3] +
";user=" + uploadParams[4] +
";password=" + uploadParams[5] +
";uploaddir=" + uploadParams[2];
if (bidix.debugMode)
sheader += ";debug=1";
sheader += ";;\r\n";
sheader += "\r\n" + "--" + boundary + "\r\n";
sheader += "Content-disposition: form-data; name=\"userfile\"; filename=\""+uploadParams[1]+"\"\r\n";
sheader += "Content-Type: text/html;charset=UTF-8" + "\r\n";
sheader += "Content-Length: " + data.length + "\r\n\r\n";
// compose trailer data
var strailer = new String();
strailer = "\r\n--" + boundary + "--\r\n";
data = sheader + data + strailer;
if (bidix.debugMode) alert("about to execute Http - POST on "+uploadParams[0]+"\n with \n"+data.substr(0,500)+ " ... ");
var r = doHttp("POST",uploadParams[0],data,"multipart/form-data; boundary="+boundary,uploadParams[4],uploadParams[5],localCallback,params,null);
if (typeof r == "string")
displayMessage(r);
return r;
};
// same as Saving's updateOriginal but without convertUnicodeToUTF8 calls
bidix.upload.updateOriginal = function(original, posDiv)
{
if (!posDiv)
posDiv = locateStoreArea(original);
if((posDiv[0] == -1) || (posDiv[1] == -1)) {
alert(config.messages.invalidFileError.format([localPath]));
return;
}
var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
store.allTiddlersAsHtml() + "\n" +
original.substr(posDiv[1]);
var newSiteTitle = getPageTitle().htmlEncode();
revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
return revised;
};
//
// UploadLog
//
// config.options.chkUploadLog :
// false : no logging
// true : logging
// config.options.txtUploadLogMaxLine :
// -1 : no limit
// 0 : no Log lines but UploadLog is still in place
// n : the last n lines are only kept
// NaN : no limit (-1)
bidix.UploadLog = function() {
if (!config.options.chkUploadLog)
return; // this.tiddler = null
this.tiddler = store.getTiddler("UploadLog");
if (!this.tiddler) {
this.tiddler = new Tiddler();
this.tiddler.title = "UploadLog";
this.tiddler.text = "| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |";
this.tiddler.created = new Date();
this.tiddler.modifier = config.options.txtUserName;
this.tiddler.modified = new Date();
store.addTiddler(this.tiddler);
}
return this;
};
bidix.UploadLog.prototype.addText = function(text) {
if (!this.tiddler)
return;
// retrieve maxLine when we need it
var maxLine = parseInt(config.options.txtUploadLogMaxLine,10);
if (isNaN(maxLine))
maxLine = -1;
// add text
if (maxLine != 0)
this.tiddler.text = this.tiddler.text + text;
// Trunck to maxLine
if (maxLine >= 0) {
var textArray = this.tiddler.text.split('\n');
if (textArray.length > maxLine + 1)
textArray.splice(1,textArray.length-1-maxLine);
this.tiddler.text = textArray.join('\n');
}
// update tiddler fields
this.tiddler.modifier = config.options.txtUserName;
this.tiddler.modified = new Date();
store.addTiddler(this.tiddler);
// refresh and notifiy for immediate update
story.refreshTiddler(this.tiddler.title);
store.notify(this.tiddler.title, true);
};
bidix.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir, backupDir) {
if (!this.tiddler)
return;
var now = new Date();
var text = "\n| ";
var filename = bidix.basename(document.location.toString());
if (!filename) filename = '/';
text += now.formatString("0DD/0MM/YYYY 0hh:0mm:0ss") +" | ";
text += config.options.txtUserName + " | ";
text += "[["+filename+"|"+location + "]] |";
text += " [[" + bidix.basename(storeUrl) + "|" + storeUrl + "]] | ";
text += uploadDir + " | ";
text += "[[" + bidix.basename(toFilename) + " | " +toFilename + "]] | ";
text += backupDir + " |";
this.addText(text);
};
bidix.UploadLog.prototype.endUpload = function(status) {
if (!this.tiddler)
return;
this.addText(" "+status+" |");
};
//
// Utilities
//
bidix.checkPlugin = function(plugin, major, minor, revision) {
var ext = version.extensions[plugin];
if (!
(ext &&
((ext.major > major) ||
((ext.major == major) && (ext.minor > minor)) ||
((ext.major == major) && (ext.minor == minor) && (ext.revision >= revision))))) {
// write error in PluginManager
if (pluginInfo)
pluginInfo.log.push("Requires " + plugin + " " + major + "." + minor + "." + revision);
eval(plugin); // generate an error : "Error: ReferenceError: xxxx is not defined"
}
};
bidix.dirname = function(filePath) {
if (!filePath)
return;
var lastpos;
if ((lastpos = filePath.lastIndexOf("/")) != -1) {
return filePath.substring(0, lastpos);
} else {
return filePath.substring(0, filePath.lastIndexOf("\\"));
}
};
bidix.basename = function(filePath) {
if (!filePath)
return;
var lastpos;
if ((lastpos = filePath.lastIndexOf("#")) != -1)
filePath = filePath.substring(0, lastpos);
if ((lastpos = filePath.lastIndexOf("/")) != -1) {
return filePath.substring(lastpos + 1);
} else
return filePath.substring(filePath.lastIndexOf("\\")+1);
};
bidix.initOption = function(name,value) {
if (!config.options[name])
config.options[name] = value;
};
//
// Initializations
//
// require PasswordOptionPlugin 1.0.1 or better
bidix.checkPlugin("PasswordOptionPlugin", 1, 0, 1);
// styleSheet
setStylesheet('.txtUploadStoreUrl, .txtUploadBackupDir, .txtUploadDir {width: 22em;}',"uploadPluginStyles");
//optionsDesc
merge(config.optionsDesc,{
txtUploadStoreUrl: "Url of the UploadService script (default: store.php)",
txtUploadFilename: "Filename of the uploaded file (default: in index.html)",
txtUploadDir: "Relative Directory where to store the file (default: . (downloadService directory))",
txtUploadBackupDir: "Relative Directory where to backup the file. If empty no backup. (default: ''(empty))",
txtUploadUserName: "Upload Username",
pasUploadPassword: "Upload Password",
chkUploadLog: "do Logging in UploadLog (default: true)",
txtUploadLogMaxLine: "Maximum of lines in UploadLog (default: 10)"
});
// Options Initializations
bidix.initOption('txtUploadStoreUrl','');
bidix.initOption('txtUploadFilename','');
bidix.initOption('txtUploadDir','');
bidix.initOption('txtUploadBackupDir','');
bidix.initOption('txtUploadUserName','');
bidix.initOption('pasUploadPassword','');
bidix.initOption('chkUploadLog',true);
bidix.initOption('txtUploadLogMaxLine','10');
/* don't want this for tiddlyspot sites
// Backstage
merge(config.tasks,{
uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");
*/
//}}}
For using SOF you only have to build the 'impl' project (see [[Project Structure]]) in the SOF directory.
Please look [[here|http://www.codeproject.com/KB/library/Remote_SOF.aspx]] for a short introduction into Remote SOF.