Experiments: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
|||
(26 intermediate revisions by the same user not shown) | |||
Line 23: | Line 23: | ||
*[http://www.mozilla.org/scriptable/XPCShell.html XPCShell] can be a good way to run sanity and unit tests on code before trying it out in Thunderbird, though I haven't yet figured out how to get it to use my Thunderforce testing profile in Thunderbird | *[http://www.mozilla.org/scriptable/XPCShell.html XPCShell] can be a good way to run sanity and unit tests on code before trying it out in Thunderbird, though I haven't yet figured out how to get it to use my Thunderforce testing profile in Thunderbird | ||
**Apparently, the environment in XPCShell is very limited, and the profile information is not loaded by default. The profile manager is not accessible out-of-the-box, either. I'm thinking of performing the XPCOM tests within Thunderbird using a [http://xulunit.mozdev.org/ XULUnit] instead, which can also test the user interface | **Apparently, the environment in XPCShell is very limited, and the profile information is not loaded by default. The profile manager is not accessible out-of-the-box, either. I'm thinking of performing the XPCOM tests within Thunderbird using a [http://xulunit.mozdev.org/ XULUnit] instead, which can also test the user interface | ||
*I need to make sure that "throw Components.Exception(message, Components.results.NS_ERROR_FAILURE);" works as a way to throw an exception with a detail string (TODO) | *I need to make sure that "throw [http://developer.mozilla.org/en/docs/Components.Exception Components.Exception(message, Components.results.NS_ERROR_FAILURE);]" works as a way to throw an exception with a detail string (TODO) | ||
*Is there a way to include one JavaScript file into another in XPCOM components? I really hope there is.. | *Is there a way to include one JavaScript file into another in XPCOM components? I really hope there is.. | ||
**I defined various quality assurance functions such as assert(), assertNotNull(), and assertEquals(), but it would be nice to have this defined once instead of in each XPCOM object. Perhaps these QA functions should be in their own XPCOM object? | **I defined various quality assurance functions such as assert(), assertNotNull(), and assertEquals(), but it would be nice to have this defined once instead of in each XPCOM object. Perhaps these QA functions should be in their own XPCOM object? | ||
*Error codes are in nsError.h | |||
*The password manager is easy to access. I'm going to simply adapt the existing code in the nsMsgIncomingServer.cpp file into JavaScript | |||
*The data layer should be slightly changed to fit into the RDF framework so that once a login takes place, it stays active until Thunderbird exits or its account is deleted | |||
==Use the SQLite engine that ships with Thunderbird== | ==Use the SQLite engine that ships with Thunderbird== | ||
*It's usable :-) | *It's usable :-) | ||
*This is presently in the nsThunderforceServerTests.js file as testSQLite | |||
==Running tests in Thunderbird using XULUnit== | |||
*Success :-). I now have the XULUnit test structure set up as a Thunderbird extension [https://www.moonlightdesign.org/thunderforce/svn/trunk/tests/ in its own folder] | |||
*With the help of [http://developer.mozilla.org/en/docs/Chrome:_Command_Line an article on Mozilla's wiki], Thunderbird now has a command line option to run the XULUnit tests, which is -thunderforcetest | |||
*The test framework will be extended to write out the test results to a file so that the tests can be run in pure command line mode | |||
**Graphical tests can be run from a console, too, with the magic of Xvnc on Linux systems (Linux is my primary dev environment). On Windows, the test window will be visible unless if Mozilla has a special headless way of loading XUL, which might change the dynamics of a test too much in that it's not testing in a realistic environment | |||
==Determine a sensible approach for implementing Thunderbird folders== | ==Determine a sensible approach for implementing Thunderbird folders== | ||
*The [http://www.xulplanet.com/references/xpcomref/ifaces/nsIMsgFolder.html nsIMsgFolder folder interface] has a ''lot'' of properties and methods in it | |||
*Different subclasses can be used for different types of entities, such as documents, cases, accounts, emailmessage, etc | |||
*Filters interoperate with folders, though I think it's optional via a getter in the account | |||
*The class and inheritance structure for the folders should be designed ahead of time and then implemented | |||
*Because JavaScript-based XPCOM classes have to be implemented in one JavaScript file, the Thunderforce folder implementation will likely be a large file | |||
**Perhaps a simple script can be constructed that concatenates the parts together into one file, especially for subclasses and large functional sections | |||
**Should Ant be used to do this and other basic build tasks? Shell scripts? For now, it's possible to create a simple shell script, though it's probably better to use something like Ant or Autoconf/Automake for the long term. Thoughts? | |||
==Determine a sensible approach for implementing a Thunderbird address book== | ==Determine a sensible approach for implementing a Thunderbird address book== | ||
*The [http://www.xulplanet.com/references/xpcomref/group_AddressBook.html address book interfaces] can be implemented | |||
*This might be a nice simple interface to implement either initially or in parallel with the account and folders | |||
*The nsDirPrefs.h file in the Mozilla source code contains various helpful constants | |||
*The nsDirPrefs.cpp file contains DIR_AddNewAddressBook | |||
*The entry point for creating an address book is implemented in nsAbBSDirectory.cpp in nsAbBSDirectory::CreateNewDirectory | |||
*The ldap_2.autoComplete preference controls automatic directory lookups | |||
*Oddly enough, "Personal Address Book" exists as ldap_2.servers.pab and "Collected Addresses" exists as ldap_2.servers.history, even though neither are LDAP servers (weird, but whatever..) | |||
*DIR_GetServerPreferences in nsDirPrefs.cpp loads the address book preferences into memory, which is typically called by DIR_GetDirServers | |||
**This calls dir_GetPrefsFrom45Branch in nsDirPrefs.cpp | |||
*CreateDirectoriesFromFactory in nsAbBSDirectory.cpp calls the factory to create the address book | |||
*The filename property will need to be set so that Thunderbird won't create a personal address book file | |||
*The nsIAbDirFactory is retrieved using the directory factory service [http://www.xulplanet.com/references/xpcomref/ifaces/nsIAbDirFactoryService.html nsIAbDirFactoryService], which we will need to register our factory with | |||
*Events should be propagated using the [http://www.xulplanet.com/references/xpcomref/comps/c_addressbookservicessession1.html @mozilla.org/addressbook/services/session;1 address book service] | |||
*GetChildNodes in nsAbBSDirectory.cpp appears to lazily initialize the in-memory store of address books by using the nsIAbDirFactory objects of the relevant types via the nsIAbDirFactoryService | |||
==Determine a sensible approach for implementing Thunderbird extension details== | ==Determine a sensible approach for implementing Thunderbird extension details== | ||
*Examples include the "about" window and the preferences | *Examples include the "about" window and the preferences | ||
==Determine a sensible approach for implementing a Thunderbird | ==Determine a sensible approach for implementing a Thunderbird URI handler for Salesforce== | ||
*The [http://www.xulplanet.com/references/xpcomref/ifaces/nsIURI.html nsIURI] class can be implemented to represent unique Salesforce.com paths, which are in the form of salesforce://thunderbirdAccountId/path_in_salesforce | |||
*Several interfaces will need to be implemented, and these can perform their duties by using the [[Notional architecture#Salesforce.com_data_layer_.28model.29|Salesforce.com data layer]]: | |||
**[http://www.xulplanet.com/references/xpcomref/ifaces/nsIProtocolHandler.html nsIProtocolHandler] | |||
**[http://www.xulplanet.com/references/xpcomref/ifaces/nsIMsgProtocolInfo.html nsIMsgProtocolInfo] (initial implementation already exists in Subversion) | |||
**[http://www.xulplanet.com/references/xpcomref/ifaces/nsIMsgMessageFetchPartService.html nsIMsgMessageFetchPartService] | |||
**[http://www.xulplanet.com/references/xpcomref/ifaces/nsIMsgMessageService.html nsIMsgMessageService] | |||
==Determine a sensible approach for implementing Thunderbird filters== | ==Determine a sensible approach for implementing Thunderbird filters== | ||
*Filters can probably happen after M1.. Just getting the account, folders, and address books up and running is a lot of work | |||
==Determine a sensible approach for implementing Thunderbird's offline mode== | ==Determine a sensible approach for implementing Thunderbird's offline mode== | ||
*Post-M1, and possibly version 2.0 | |||
==How does Thunderbird's undo/redo manager affect the offline cache?== | ==How does Thunderbird's undo/redo manager affect the offline cache?== | ||
*The [http://www.xulplanet.com/references/xpcomref/ifaces/nsIMessenger.html#method_Undo nsIMessenger] interface contains the Undo, Redo, CanUndo, and CanRedo functions. That interface is implemented by nsMessenger.cpp, which uses [http://www.xulplanet.com/references/xpcomref/ifaces/nsITransaction.html nsITransaction] object instances | |||
*The [http://www.xulplanet.com/references/xpcomref/ifaces/nsITransactionManager.html nsITransactionManager] transaction manager can be obtained through nsIMsgWindow through the GetTransactionManager() function (line 2246 of nsImapMailFolder.cpp is one example) | |||
*After getting the transaction manager, a nsITransaction that can perform, undo, and optionally coalesce transactions gets passed in to the [http://www.xulplanet.com/references/xpcomref/ifaces/nsITransactionManager.html#method_doTransaction transaction manager's doTransaction() method] | |||
*Undoable actions will thus be implemented as nsITransaction objects. This can potentially help out with splitting up Thunderforce into more granular files as separate XPCOM objects, though it's likely that some undoable actions will need access to the folder's or account's internal state | |||
*Because the window is needed, we'll probably make only user-driven operations undoable, which is typically how most programs' undo/redo functions work anyway | |||
*[http://www.sqlite.org/lang_transaction.html SQLite does not support nested transactions] (I was originally thinking of possibly taking advantage of that to easily implement undo/redo) | |||
*The undo/redo state is typically driven by a Thunderforce session, so one implementation possibility is to not concern the offline cache with versioning and, instead, keep undo/redo state in memory. The offline cache would thus contain the committed state, and the nsITransaction would have to undo its changes based on what its operation was |
Latest revision as of 18:03, 16 September 2007
This page lists the experiments that resulted from the notional architecture review.
Using the Salesforce.com AJAX toolkit in a Thunderbird extension
- This works perfectly and exists in the current Subversion source code
- For production, the AJAX toolkit will exist within an XPCOM interface implementation consistent with the Salesforce.com data layer in the architecture
Determine a sensible approach for implementing a Thunderbird account
- XULPlanet.com is a great source of documentation for the Mozilla platform's interfaces
- The IDL files in the Mozilla source code do not indicate interface inheritance. Apparently, all the inheritance takes place in the interface implementations
- Setting a preference char value on a preference branch apparently doesn't work when no values existed in that preference branch (or maybe that's always the case? I'm not sure. This is when I was using nsIPrefService instead of nsIPref to get the branch, so perhaps that was the reason?). Setting that preference using nsIPref instead of nsIPrefBranch appears to work fabulously
- The setters for nsIMsgProtocolInfo.defaultLocalPath and nsIMsgIncomingServer.defaultLocalPath are only called by the Thunderbird profile migration code, and new account types don't (yet) need to implement it; it's called on a case-by-case basis by migration for each specific incoming server type that migration knows about, which does not include Thunderforce. To make this an even safer bet, nsRssService, which is build into Thunderbird, throws NS_ERROR_NOT_IMPLEMENTED for its defaultLocalPath setter
- When gdb is used to debug Thunderbird, the Thunderbird user interface takes a long time to start up and runs slowly. Venkman and the error console, thankfully, both work when gdb is debugging Thunderbird (with Venkman, it's a debugger within a debugger)
- The about:config display extension does not appear to work in my debug build of Thunderbird (line 105 of chrome://about_about/content/mrtech-common.js says "browserWindow has no properties")
- Returning the wrong object type in JavaScript code produces a vague NS_ERROR_FAILURE without further details. Be sure that return types are always correct
- Watch out for properties that have the [noscript] annotation. These are apparently not marked as such on XULPlanet.com, but can be seen in the interface's IDL file
- JavaScript apparently cannot extend a native C++ class. This means that Thunderforce cannot reuse the functionality built into the nsMsgIncomingServer base class implementation of nsIMsgIncomingServer unless if that part is in a native library. Having a native library reduces portability, but not having a native library increases the amount of code required in Thunderforce to re-implement the relevant parts of nsMsgIncomingServer in JavaScript as well as increasing the implementation time
- This is an architectural trade-off
- Re-implementing the necessary parts of nsMsgIncomingServer in JavaScript actually isn't that bad and, in all functions thus far, the JavaScript code is a fraction of the lines of code that the C++ versions need, though the execution time is probably about the same or slower than C++
- While thinking about the architectural trade-off above, I realized that any of the above approaches will require at least automated nightly testing with the latest Thunderbird code to ensure that changes to Thunderbird don't break Thunderforce for its use
- The automated update mechanism in Thunderbird 2.0 and above can make changes to Thunderforce as painless as possible to its users, and the automated nightly testing can help the Thunderforce dev team greatly reduce the risk of new Thunderbird patch and full releases breaking Thunderforce
- If a native library is used for the account code, it's possible that interface changes to nsIMsgIncomingServer can cause Thunderbird to crash. With JavaScript, Thunderbird shouldn't crash but, instead, Thunderforce will fail to operate properly
- A detection mechanism for this to gracefully fail Thunderforce might be easier to implement when everything is in JavaScript. Perhaps this can be accomplished by automatically running a small set of unit tests whenever the version of Thunderbird changes
- XPCShell can be a good way to run sanity and unit tests on code before trying it out in Thunderbird, though I haven't yet figured out how to get it to use my Thunderforce testing profile in Thunderbird
- Apparently, the environment in XPCShell is very limited, and the profile information is not loaded by default. The profile manager is not accessible out-of-the-box, either. I'm thinking of performing the XPCOM tests within Thunderbird using a XULUnit instead, which can also test the user interface
- I need to make sure that "throw Components.Exception(message, Components.results.NS_ERROR_FAILURE);" works as a way to throw an exception with a detail string (TODO)
- Is there a way to include one JavaScript file into another in XPCOM components? I really hope there is..
- I defined various quality assurance functions such as assert(), assertNotNull(), and assertEquals(), but it would be nice to have this defined once instead of in each XPCOM object. Perhaps these QA functions should be in their own XPCOM object?
- Error codes are in nsError.h
- The password manager is easy to access. I'm going to simply adapt the existing code in the nsMsgIncomingServer.cpp file into JavaScript
- The data layer should be slightly changed to fit into the RDF framework so that once a login takes place, it stays active until Thunderbird exits or its account is deleted
Use the SQLite engine that ships with Thunderbird
- It's usable :-)
- This is presently in the nsThunderforceServerTests.js file as testSQLite
Running tests in Thunderbird using XULUnit
- Success :-). I now have the XULUnit test structure set up as a Thunderbird extension in its own folder
- With the help of an article on Mozilla's wiki, Thunderbird now has a command line option to run the XULUnit tests, which is -thunderforcetest
- The test framework will be extended to write out the test results to a file so that the tests can be run in pure command line mode
- Graphical tests can be run from a console, too, with the magic of Xvnc on Linux systems (Linux is my primary dev environment). On Windows, the test window will be visible unless if Mozilla has a special headless way of loading XUL, which might change the dynamics of a test too much in that it's not testing in a realistic environment
Determine a sensible approach for implementing Thunderbird folders
- The nsIMsgFolder folder interface has a lot of properties and methods in it
- Different subclasses can be used for different types of entities, such as documents, cases, accounts, emailmessage, etc
- Filters interoperate with folders, though I think it's optional via a getter in the account
- The class and inheritance structure for the folders should be designed ahead of time and then implemented
- Because JavaScript-based XPCOM classes have to be implemented in one JavaScript file, the Thunderforce folder implementation will likely be a large file
- Perhaps a simple script can be constructed that concatenates the parts together into one file, especially for subclasses and large functional sections
- Should Ant be used to do this and other basic build tasks? Shell scripts? For now, it's possible to create a simple shell script, though it's probably better to use something like Ant or Autoconf/Automake for the long term. Thoughts?
Determine a sensible approach for implementing a Thunderbird address book
- The address book interfaces can be implemented
- This might be a nice simple interface to implement either initially or in parallel with the account and folders
- The nsDirPrefs.h file in the Mozilla source code contains various helpful constants
- The nsDirPrefs.cpp file contains DIR_AddNewAddressBook
- The entry point for creating an address book is implemented in nsAbBSDirectory.cpp in nsAbBSDirectory::CreateNewDirectory
- The ldap_2.autoComplete preference controls automatic directory lookups
- Oddly enough, "Personal Address Book" exists as ldap_2.servers.pab and "Collected Addresses" exists as ldap_2.servers.history, even though neither are LDAP servers (weird, but whatever..)
- DIR_GetServerPreferences in nsDirPrefs.cpp loads the address book preferences into memory, which is typically called by DIR_GetDirServers
- This calls dir_GetPrefsFrom45Branch in nsDirPrefs.cpp
- CreateDirectoriesFromFactory in nsAbBSDirectory.cpp calls the factory to create the address book
- The filename property will need to be set so that Thunderbird won't create a personal address book file
- The nsIAbDirFactory is retrieved using the directory factory service nsIAbDirFactoryService, which we will need to register our factory with
- Events should be propagated using the @mozilla.org/addressbook/services/session;1 address book service
- GetChildNodes in nsAbBSDirectory.cpp appears to lazily initialize the in-memory store of address books by using the nsIAbDirFactory objects of the relevant types via the nsIAbDirFactoryService
Determine a sensible approach for implementing Thunderbird extension details
- Examples include the "about" window and the preferences
Determine a sensible approach for implementing a Thunderbird URI handler for Salesforce
- The nsIURI class can be implemented to represent unique Salesforce.com paths, which are in the form of salesforce://thunderbirdAccountId/path_in_salesforce
- Several interfaces will need to be implemented, and these can perform their duties by using the Salesforce.com data layer:
- nsIProtocolHandler
- nsIMsgProtocolInfo (initial implementation already exists in Subversion)
- nsIMsgMessageFetchPartService
- nsIMsgMessageService
Determine a sensible approach for implementing Thunderbird filters
- Filters can probably happen after M1.. Just getting the account, folders, and address books up and running is a lot of work
Determine a sensible approach for implementing Thunderbird's offline mode
- Post-M1, and possibly version 2.0
How does Thunderbird's undo/redo manager affect the offline cache?
- The nsIMessenger interface contains the Undo, Redo, CanUndo, and CanRedo functions. That interface is implemented by nsMessenger.cpp, which uses nsITransaction object instances
- The nsITransactionManager transaction manager can be obtained through nsIMsgWindow through the GetTransactionManager() function (line 2246 of nsImapMailFolder.cpp is one example)
- After getting the transaction manager, a nsITransaction that can perform, undo, and optionally coalesce transactions gets passed in to the transaction manager's doTransaction() method
- Undoable actions will thus be implemented as nsITransaction objects. This can potentially help out with splitting up Thunderforce into more granular files as separate XPCOM objects, though it's likely that some undoable actions will need access to the folder's or account's internal state
- Because the window is needed, we'll probably make only user-driven operations undoable, which is typically how most programs' undo/redo functions work anyway
- SQLite does not support nested transactions (I was originally thinking of possibly taking advantage of that to easily implement undo/redo)
- The undo/redo state is typically driven by a Thunderforce session, so one implementation possibility is to not concern the offline cache with versioning and, instead, keep undo/redo state in memory. The offline cache would thus contain the committed state, and the nsITransaction would have to undo its changes based on what its operation was