1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: comm_bas.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_automation.hxx"
34 #include "comm_bas.hxx"
35 #include <tools/errcode.hxx>
36 #include <basic/sbxobj.hxx>
37 #include <basic/sbx.hxx>
38 #ifndef __SBX_SBXVARIABLE_HXX //autogen
39 #include <basic/sbxvar.hxx>
41 #include <vcl/svapp.hxx>
42 #include <automation/communi.hxx>
43 #ifndef _BASIC_TTRESHLP_HXX
44 #include <basic/ttstrhlp.hxx>
47 // Der CommunicationManager hat folgende Elemente:
51 // CommunicationLink StartCommunication( Host, Port )
52 // StopAllCommunication // Alle Kommunikation wird abgebrochen
53 // BOOL IsCommunicationRunning // Läuft noch irgendwas
54 // String GetMyName Der eigene Name
55 // BOOL IsLinkValid( CommunicationLink ) // Ist dieser Link noch gültig
56 // SetCommunicationEventHandler( String ) // Diese Funktion wird aufgerufen bei jedem Event
58 // Der CommunicationLink hat folgende Elemente:
62 // StopCommunication Die Kommunikation wird abgebrochen
63 // String GetMyName Der eigene Name
64 // String GetHostName Der Name des Anderen
65 // Send(String ) String an den Partner schicken
66 // String GetString Ergebnis des letzten Empfangs
69 // Diese Implementation ist ein Beispiel fuer eine tabellengesteuerte
70 // Version, die sehr viele Elemente enthalten kann. Die Elemente werden
71 // je nach Bedarf aus der Tabelle in das Objekt uebernommen.
73 // Das nArgs-Feld eines Tabelleneintrags ist wie folgt verschluesselt:
75 #define _ARGSMASK 0x00FF // Bis zu 255 Argumente
76 #define _RWMASK 0x0F00 // Maske fuer R/W-Bits
77 #define _TYPEMASK 0xF000 // Maske fuer den Typ des Eintrags
79 #define _READ 0x0100 // kann gelesen werden
80 #define _BWRITE 0x0200 // kann as Lvalue verwendet werden
81 #define _LVALUE _BWRITE // kann as Lvalue verwendet werden
82 #define _READWRITE 0x0300 // beides
83 #define _OPT 0x0400 // TRUE: optionaler Parameter
84 #define _METHOD 0x1000 // Masken-Bit fuer eine Methode
85 #define _PROPERTY 0x2000 // Masken-Bit fuer eine Property
86 #define _COLL 0x4000 // Masken-Bit fuer eine Collection
87 // Kombination von oberen Bits:
88 #define _FUNCTION 0x1100 // Maske fuer Function
89 #define _LFUNCTION 0x1300 // Maske fuer Function, die auch als Lvalue geht
90 #define _ROPROP 0x2100 // Maske Read Only-Property
91 #define _WOPROP 0x2200 // Maske Write Only-Property
92 #define _RWPROP 0x2300 // Maske Read/Write-Property
93 #define _COLLPROP 0x4100 // Maske Read-Collection-Element
95 #define COLLNAME "Elements" // Name der Collection, hier mal hart verdrahtet
99 CommunicationWrapper::Methods
CommunicationWrapper::aManagerMethods
[] = {
100 // Neue Kommunikation aufbauen
101 { "StartCommunication", SbxEMPTY
, &CommunicationWrapper::MStartCommunication
, 2 | _FUNCTION
},
102 // Zwei Named Parameter
103 { "Host", SbxSTRING
, NULL
, 0 },
104 { "Port", SbxLONG
, NULL
, 0 },
105 // Alle Kommunikation wird abgebrochen
106 { "StopAllCommunication", SbxEMPTY
, &CommunicationWrapper::MStopAllCommunication
, 0 | _FUNCTION
},
107 // Läuft noch irgendwas
108 { "IsCommunicationRunning", SbxBOOL
, &CommunicationWrapper::MIsCommunicationRunning
, 0 | _FUNCTION
},
109 // Hostname als FQDN erfragen
110 { "GetMyName", SbxSTRING
, &CommunicationWrapper::MGetMyName
, 0 | _FUNCTION
},
111 // Abfragen ob der Link überhaupt noch gültig ist
112 { "IsLinkValid", SbxBOOL
, &CommunicationWrapper::MIsLinkValid
, 1 | _FUNCTION
},
113 // Ein Named Parameter
114 { "Link", SbxOBJECT
, NULL
, 0 },
115 // Dieser Handler wird dauernd gerufen
116 { "SetCommunicationEventHandler", SbxEMPTY
, &CommunicationWrapper::MSetCommunicationEventHandler
, 1 | _FUNCTION
},
117 // Ein Named Parameter
118 { "FuncName", SbxSTRING
, NULL
, 0 },
120 { NULL
, SbxNULL
, NULL
, -1 }}; // Tabellenende
127 CommunicationWrapper::Methods
CommunicationWrapper::aLinkMethods
[] = {
128 // Die Kommunikation wird abgebrochen
129 { "StopCommunication", SbxEMPTY
, &CommunicationWrapper::LStopCommunication
, 0 | _FUNCTION
},
131 { "GetMyName", SbxSTRING
, &CommunicationWrapper::LGetMyName
, 0 | _FUNCTION
},
132 // Der Name des Anderen
133 { "GetHostName", SbxSTRING
, &CommunicationWrapper::LGetHostName
, 0 | _FUNCTION
},
134 // String an den Partner schicken
135 { "Send", SbxEMPTY
, &CommunicationWrapper::LSend
, 1 | _FUNCTION
},
136 // Ein Named Parameter
137 { "SendString", SbxSTRING
, NULL
, 0 },
138 // Ergebnis des letzten Empfangs
139 { "GetString", SbxSTRING
, &CommunicationWrapper::LGetString
, 0 | _FUNCTION
},
141 { NULL
, SbxNULL
, NULL
, -1 }}; // Tabellenende
147 // Konstruktor für den Manager
148 CommunicationWrapper::CommunicationWrapper( const String
& rClass
) : SbxObject( rClass
)
150 , m_bIsManager( TRUE
)
151 , m_bCatchOpen( FALSE
)
154 // SetName( CUniString("Manager") );
155 m_pMethods
= &aManagerMethods
[0];
156 m_pManager
= new CommunicationManagerClientViaSocket
;
157 m_pManager
->SetConnectionOpenedHdl( LINK( this, CommunicationWrapper
, Open
) );
158 m_pManager
->SetConnectionClosedHdl( LINK( this, CommunicationWrapper
, Close
) );
159 m_pManager
->SetDataReceivedHdl( LINK( this, CommunicationWrapper
, Data
) );
162 // Konstruktor für den Link
163 CommunicationWrapper::CommunicationWrapper( CommunicationLink
*pThisLink
) : SbxObject( CUniString("Link") )
164 , m_pLink( pThisLink
)
165 , m_bIsManager( FALSE
)
166 , m_bCatchOpen( FALSE
)
169 m_pMethods
= &aLinkMethods
[0];
170 m_pManager
= (CommunicationManagerClientViaSocket
*)pThisLink
->GetCommunicationManager();
174 CommunicationWrapper::~CommunicationWrapper()
181 // Suche nach einem Element:
182 // Hier wird linear durch die Methodentabelle gegangen, bis eine
183 // passende Methode gefunden wurde.
184 // Wenn die Methode/Property nicht gefunden wurde, nur NULL ohne
185 // Fehlercode zurueckliefern, da so auch eine ganze Chain von
186 // Objekten nach der Methode/Property befragt werden kann.
188 SbxVariable
* CommunicationWrapper::Find( const String
& rName
, SbxClassType t
)
190 // Ist das Element bereits vorhanden?
191 SbxVariable
* pRes
= SbxObject::Find( rName
, t
);
192 if( !pRes
&& t
!= SbxCLASS_OBJECT
)
195 Methods
* p
= m_pMethods
;
198 while( p
->nArgs
!= -1 )
200 if( rName
.CompareIgnoreCaseToAscii( p
->pName
) == COMPARE_EQUAL
)
202 bFound
= TRUE
; break;
204 nIndex
+= ( p
->nArgs
& _ARGSMASK
) + 1;
205 p
= m_pMethods
+ nIndex
;
209 // Args-Felder isolieren:
210 short nAccess
= ( p
->nArgs
& _RWMASK
) >> 8;
211 short nType
= ( p
->nArgs
& _TYPEMASK
);
212 String
aName( p
->pName
, RTL_TEXTENCODING_ASCII_US
);
213 SbxClassType eCT
= SbxCLASS_OBJECT
;
214 if( nType
& _PROPERTY
)
215 eCT
= SbxCLASS_PROPERTY
;
216 else if( nType
& _METHOD
)
217 eCT
= SbxCLASS_METHOD
;
218 pRes
= Make( aName
, eCT
, p
->eType
);
219 // Wir setzen den Array-Index + 1, da ja noch andere
220 // Standard-Properties existieren, die auch aktiviert
222 pRes
->SetUserData( nIndex
+ 1 );
223 pRes
->SetFlags( nAccess
);
229 // Aktivierung eines Elements oder Anfordern eines Infoblocks
231 void CommunicationWrapper::SFX_NOTIFY( SfxBroadcaster
& rBC
, const TypeId
& rBCT
,
232 const SfxHint
& rHint
, const TypeId
& rHT
)
234 const SbxHint
* pHint
= PTR_CAST(SbxHint
,&rHint
);
237 SbxVariable
* pVar
= pHint
->GetVar();
238 SbxArray
* pPar
= pVar
->GetParameters();
239 USHORT nIndex
= (USHORT
) pVar
->GetUserData();
240 // kein Index: weiterreichen!
243 ULONG t
= pHint
->GetId();
244 if( t
== SBX_HINT_INFOWANTED
)
245 pVar
->SetInfo( GetInfo( (short) pVar
->GetUserData() ) );
249 if( t
== SBX_HINT_DATACHANGED
)
251 if( t
== SBX_HINT_DATAWANTED
|| bWrite
)
253 // Parameter-Test fuer Methoden:
254 USHORT nPar
= m_pMethods
[ --nIndex
].nArgs
& 0x00FF;
255 // Element 0 ist der Returnwert
256 if( ( !pPar
&& nPar
)
257 || ( pPar
&& pPar
->Count() != nPar
+1 ) )
258 SetError( SbxERR_WRONG_ARGS
);
259 // Alles klar, man kann den Call ausfuehren
262 (this->*(m_pMethods
[ nIndex
].pFunc
))( pVar
, pPar
, bWrite
);
267 SbxObject::SFX_NOTIFY( rBC
, rBCT
, rHint
, rHT
);
271 // Zusammenbau der Infostruktur fuer einzelne Elemente
273 SbxInfo
* CommunicationWrapper::GetInfo( short nIdx
)
275 Methods
* p
= &m_pMethods
[ nIdx
];
276 // Wenn mal eine Hilfedatei zur Verfuegung steht:
277 // SbxInfo* pInfo = new SbxInfo( Hilfedateiname, p->nHelpId );
278 SbxInfo
* pRetInfo
= new SbxInfo
;
279 short nPar
= p
->nArgs
& _ARGSMASK
;
280 for( short i
= 0; i
< nPar
; i
++ )
283 String
aName( p
->pName
, RTL_TEXTENCODING_ASCII_US
);
284 USHORT nIFlags
= ( p
->nArgs
>> 8 ) & 0x03;
285 if( p
->nArgs
& _OPT
)
286 nIFlags
|= SBX_OPTIONAL
;
287 pRetInfo
->AddParam( aName
, p
->eType
, nIFlags
);
293 ////////////////////////////////////////////////////////////////////////////
295 // Hilfsmethoden für den Manager
297 IMPL_LINK( CommunicationWrapper
, Open
, CommunicationLink
*, pLink
)
302 Events( CUniString("Open"), pLink
);
306 IMPL_LINK( CommunicationWrapper
, Close
, CommunicationLink
*, pLink
)
308 Events( CUniString("Close"), pLink
);
312 IMPL_LINK( CommunicationWrapper
, Data
, CommunicationLink
*, pLink
)
314 Events( CUniString("Data"), pLink
);
318 void CommunicationWrapper::Events( String aType
, CommunicationLink
* pLink
)
320 if ( m_aEventHandlerName
.Len() )
322 SbxArrayRef pPar
= new SbxArray( SbxVARIANT
);
323 pPar
->Put( new SbxVariable( SbxSTRING
), 1 );
324 pPar
->Get( 1 )->PutString( aType
);
326 pPar
->Put( new SbxVariable( SbxOBJECT
), 2 );
327 pPar
->Get( 2 )->PutObject( new CommunicationWrapper( pLink
) );
329 Call( m_aEventHandlerName
, pPar
);
332 delete pLink
->GetServiceData(); // Stream wegschmeissen um nicht zu blockieren
336 ////////////////////////////////////////////////////////////////////////////
338 // Properties und Methoden legen beim Get (bPut = FALSE) den Returnwert
339 // im Element 0 des Argv ab; beim Put (bPut = TRUE) wird der Wert aus
340 // Element 0 gespeichert.
345 void CommunicationWrapper::MStartCommunication( SbxVariable
* pVar
, SbxArray
* pPar
, BOOL
/*bWrite*/ )
346 { // CommunicationLink StartCommunication( Host, Port )
348 if ( m_pManager
->StartCommunication( ByteString( pPar
->Get( 1 )->GetString(), RTL_TEXTENCODING_UTF8
), pPar
->Get( 2 )->GetULong() ) )
350 while ( !m_pNewLink
)
351 GetpApp()->Reschedule();
352 m_bCatchOpen
= FALSE
;
353 CommunicationWrapper
*pNewLinkWrapper
= new CommunicationWrapper( m_pNewLink
);
355 pVar
->PutObject( pNewLinkWrapper
);
360 void CommunicationWrapper::MStopAllCommunication( SbxVariable
* /*pVar*/, SbxArray
* /*pPar*/, BOOL
/*bWrite*/ )
361 { // StopAllCommunication // Alle Kommunikation wird abgebrochen
362 m_pManager
->StopCommunication();
365 void CommunicationWrapper::MIsCommunicationRunning( SbxVariable
* pVar
, SbxArray
* /*pPar*/, BOOL
/*bWrite*/ )
366 { // BOOL IsCommunicationRunning // Läuft noch irgendwas
367 pVar
->PutBool( m_pManager
->IsCommunicationRunning() );
370 void CommunicationWrapper::MGetMyName( SbxVariable
* pVar
, SbxArray
* /*pPar*/, BOOL
/*bWrite*/ )
371 { // String GetMyName Der eigene Name
372 pVar
->PutString( UniString( m_pManager
->GetMyName( CM_FQDN
), RTL_TEXTENCODING_UTF8
) );
375 void CommunicationWrapper::MIsLinkValid( SbxVariable
* pVar
, SbxArray
* pPar
, BOOL
/*bWrite*/ )
376 { // BOOL IsLinkValid( CommunicationLink ) // Ist dieser Link noch gültig
377 CommunicationWrapper
*pWrapper
= (CommunicationWrapper
*)(pPar
->Get( 1 )->GetObject());
378 pVar
->PutBool( m_pManager
->IsLinkValid( pWrapper
->GetCommunicationLink() ) );
381 void CommunicationWrapper::MSetCommunicationEventHandler( SbxVariable
* /*pVar*/, SbxArray
* pPar
, BOOL
/*bWrite*/ )
382 { // SetCommunicationEventHandler( String ) // Diese Funktion wird aufgerufen bei jedem Event
383 m_aEventHandlerName
= pPar
->Get( 1 )->GetString();
391 void CommunicationWrapper::LStopCommunication( SbxVariable
* /*pVar*/, SbxArray
* /*pPar*/, BOOL
/*bWrite*/ )
392 { // StopCommunication Die Kommunikation wird abgebrochen
393 m_pLink
->StopCommunication();
396 void CommunicationWrapper::LGetMyName( SbxVariable
* pVar
, SbxArray
* /*pPar*/, BOOL
/*bWrite*/ )
397 { // String GetMyName Der eigene Name
398 pVar
->PutString( UniString( m_pLink
->GetMyName( CM_FQDN
), RTL_TEXTENCODING_UTF8
) );
401 void CommunicationWrapper::LGetHostName( SbxVariable
* pVar
, SbxArray
* /*pPar*/, BOOL
/*bWrite*/ )
402 { // String GetHostName Der Name des Anderen
403 pVar
->PutString( UniString( m_pLink
->GetCommunicationPartner( CM_FQDN
), RTL_TEXTENCODING_UTF8
) );
406 void CommunicationWrapper::LSend( SbxVariable
* /*pVar*/, SbxArray
* pPar
, BOOL
/*bWrite*/ )
407 { // Send(String ) String an den Partner schicken
408 SvStream
*pSendStream
= m_pLink
->GetBestCommunicationStream();
409 String aSendString
= pPar
->Get( 1 )->GetString();
410 pSendStream
->WriteByteString( aSendString
, RTL_TEXTENCODING_UTF8
);
411 m_pLink
->TransferDataStream( pSendStream
);
415 void CommunicationWrapper::LGetString( SbxVariable
* pVar
, SbxArray
* /*pPar*/, BOOL
/*bWrite*/ )
416 { // String GetString Ergebnis des letzten Empfangs
417 SvStream
*pReceiveStream
= m_pLink
->GetServiceData();
418 if ( pReceiveStream
)
420 ULONG nLength
= pReceiveStream
->Seek( STREAM_SEEK_TO_END
);
421 pReceiveStream
->Seek( STREAM_SEEK_TO_BEGIN
);
422 char *pBuffer
= new char[nLength
];
423 pReceiveStream
->Read( pBuffer
, nLength
);
425 pBuffer
, sal::static_int_cast
< xub_StrLen
>( nLength
),
426 RTL_TEXTENCODING_UTF8
);
428 pVar
->PutString( aReceive
);
429 delete pReceiveStream
;
432 pVar
->PutString( UniString() );
437 // Die Factory legt unser Objekte an.
439 SbxObject
* CommunicationFactory::CreateObject( const String
& rClass
)
441 if( rClass
.CompareIgnoreCaseToAscii( "CommunicationManager" ) == COMPARE_EQUAL
)
442 return new CommunicationWrapper( rClass
);