• No results found

Customizable Software Engineering Environments for Flexible Distributed Software Teams

N/A
N/A
Protected

Academic year: 2021

Share "Customizable Software Engineering Environments for Flexible Distributed Software Teams"

Copied!
8
0
0

Loading.... (view fulltext now)

Full text

(1)

Customizable Software Engineering Environments for Flexible Distributed

Software Teams

Robert P. Biuk-Aghai

Faculty of Science and Technology

University of Macau

E-mail:

fst.robert@umac.mo

Abstract

The recent interest in carrying out software engineering in a distributed manner could lead to a future increase in the contracting of software engineers, grouped into flexible, distributed software teams. One of the implications will be a requirement for more customizable software engineering environments to meet the diverse requirements of different projects. This paper examines customizability issues and suggests the use of component-based systems to achieve a high degree of customizability. A component model for software tools is presented in which tool components are characterized by the services they provide, require and op-tionally can use. Implementations of early prototypes, us-ing JavaBeans components and employus-ing the JavaBeans Activation Framework, are presented. The integration of legacy tools into the model is explored, and two mechanisms are presented: adapters encapsulate access to tools imple-mented in Java, and wrappers integrate other external tools.

1. Introduction

Recent years have witnessed a spate of interest in all things virtual: virtual classrooms, virtual teams, virtual or-ganizations, virtual communities, and more. A major con-tributing factor has no doubt been the Internet’s emergence from its previous relative obscurity, enabling formerly sepa-rated people and organizations to explore new ways of con-ducting their activities in a distributed manner.

Within software engineering, use of the Internet as a medium for conducting distributed software engineering ac-tivities has been on the rise in recent years, as witnessed by various reports of its application [5, 8, 9]. No doubt this trend will continue: we believe that in the future it will be common for software teams to be physically distributed and to cooperate through the support of suitable group-enabled software engineering environments.

Such a distributed software engineering paradigm has obvious advantages: project team members who are phys-ically distributed do not need to be brought together in one location, eliminating transportation and accommoda-tion costs; people with the appropriate skills can be put on a project, regardless of their location; experts with spe-cialized skills can be shared on several concurrent projects; and if staff telecommute, working from their homes, of-fice costs can be reduced or eliminated, further minimizing staff overheads. Altogether, this may well lead to a trend where staffing software projects with dynamically com-posed teams of contract staff, combining the skills and ex-pertise required for a given project, would be preferred over employing fixed teams of permanent staff with the same set of skills.

For individual contract software engineers this means that at different times they would work on different projects, with different team members, under different management, using different development methods, methodologies and processes, and requiring different software tools. This has implications in a number of areas:

Software process: Managing a software process in which team members are physically distributed and possi-bly never meet face-to-face will be challenging. If team members constantly change from one project to the next, efforts such as process improvement or even maintaining an achieved process maturity level will be difficult or impossible, as process improvement hinges very much on organizational learning. With highly dy-namic project teams, however, the very notion of an organization is put into question. This is an area with a number of open research issues, which to date have apparently not received much attention.

Collaboration support: Distributed team members col-laborating on a software project require support in communicating with each other, in sharing the prod-ucts of their work with each other, and in

(2)

coordinat-ing their work activities. Much research has been con-ducted in this area already, such as [1, 4, 5, 6, 8, 9] to name but a few.

Software tool flexibility: As the projects that a particular software engineer works on may differ greatly from each other, requiring the use of different methods and different kinds of artifacts to be produced, software tools must be flexible enough to permit customization to these widely differing requirements.

It is the last of these three aspects that the present paper is concerned with, and the following section will investi-gate software tool flexibility in more detail. In section 3 we then present a component model that enables the flexi-ble construction of software engineering environments, and section 4 describes our implementation of these ideas in a set of early prototypes. In section 5 we explore possibilities for integrating legacy software tools, while section 6 offers a number of conclusions and points out areas for further work.

2. Customizability

As indicated above, the focus of our work is on support-ing flexible software teams consistsupport-ing of contracted ware engineers whose work may involve very different soft-ware projects at different times. Differences are related to application area, development methodology, design nota-tion, programming language, etc. Consequently, the soft-ware engineering environment and its composite tools used by the software engineer will need to be adapted or changed with every new project to support the project’s requirements and to enable the software engineer to produce required ar-tifacts (documents, diagrams, program code, etc.). It does not seem realistic, therefore, to try to construct an all-encompassing software engineering environment that can handle every methodology and be used for every software project, as new methods are constantly created and even for established methods a project may apply them in its own id-iosyncratic way. Instead we advocate the use of customiz-able software engineering environments that can be adapted to a current set of requirements. The necessary adaptations could range from configuring an existing tool’s options, to adding a few tools that can produce certain required de-sign diagrams, to hooking up different software configu-ration management repositories residing somewhere on the network, to completely replacing an entire toolset with one that is needed for a specific methodology. All such cus-tomizations, however, should be easily performed by end-users without requiring any conventional programming.

Customizability (or adaptability or tailorability) of soft-ware systems has been a research topic in the area of CSCW for many years. Systems can support customizability in a

number of ways. If application designers have anticipated alternative future uses of their software, the application can make this functionality available by letting users make ap-propriate preference or parameter settings. For example, a design diagramming tool could be set up to produce dif-ferent kinds of design diagrams. Another degree of cus-tomizability is possible by exposing access to internal oper-ations through an application programming interface (API). A CASE environment could, for example, allow users to develop their own diagramming tool that can exchange data with the rest of the CASE system, such as storing and re-trieving diagrams in the CASE repository. This approach thus lets users extend an existing system through add-ons. Yet another approach is to let the entire system be compos-able from pre-fabricated tool components. This removes the barrier between the “core” system and the add-on— everything is part of the system’s core.

Stiemerling and Cremers [10] have identified three cate-gories of tailoring applicable to systems that are composed from software components: (1) changing parameters of sin-gle components; (2) changing the composition of compo-nents; and (3) changing or extending the implementation of components.

These three categories encompass complementary cus-tomizability options, each one suited for a different de-gree of required change, ranging from component-local to system-wide tailoring. This framework for adapting com-ponent systems is well-suited to the requirements of flexi-ble software engineering environments. Contract software engineers will configure existing tool components, will re-arrange the composition of their tools as needed, and if nec-essary will acquire new components to plug into their soft-ware engineering environment.

Based on these usage scenarios, we have developed a component model for software engineering tools that allows the flexible assembly of software engineering environments. The following section presents details of this model.

3. Component Model

Software engineering (CASE) environments tend to be large, complex entities, consisting of a potentially large number of individual but interoperable software tools that are integrated in one system. Interoperability here means that distinct tools are able to invoke each other and each other’s functions and pass data and control to each other. To achieve a high degree of customizability of these systems, we should adopt a composable rather than a monolithic ar-chitecture. This enables individual tools to be plugged to-gether in order to create the software engineering environ-ment desired. A problem which may exist in monolithic software engineering environments is the high degree of in-terdependence, or coupling, among tools. In a composable

(3)

Component Service Type

1 Repository a List files P

b Get file P

c Put file P

. . . .

2 Rep. Browser a List files R

b Get file R

c Put file R

d Compile file O

e Edit file O

. . . .

3 Editor a Edit file P

b Jump to line P c Get file O d Put file O e Compile file O . . . .

4 Compiler a Compile file P

b Jump to line

O

. . . .

Types of service: P: Provided; R: Required; O: Optional

Table 1. Simplified extract of service directory for four tool components

architecture, individual tools, though interoperable and inte-grated, should depend on the presence or functions of other tools to the smallest extent possible. For example, it would be useful for an entity-relationship diagramming tool to be able to invoke a code generation tool which would translate an ER diagram into SQL data definition statements. How-ever, if such a code generator is not available, the diagram-ming tool should still be able to operate, though with re-duced functionality. The design goal therefore is “enabling as much as possible while requiring as little as possible”.

We define a component model in which individual tool components are themselves fully-functional tools, i.e. they provide a significant amount of functionality and are not, say, low-level building blocks for the construction of tools. This produces a coarse-grained component model. The rea-son for not adopting a more fine-grained model is that as the granule size decreases, the effort of assembling compo-nents and the required knowledge of component semantics increases, defeating the goal of easy customizability by end-users (albeit knowledgable ones in our case).

Individual components will rarely be able to operate on their own, but will require some basic functionality from other components. For example, most diagramming and editing tools require access to a software repository which could be provided by a common repository tool. We say that a tool makes use of and offers services from/to other tools. For each tool we can define:

Provided services: A set of services which the tool makes available for other tools to use.

Required services: A set of essential services which the tool requires in order to be able to function. This set should be quite small in practice.

Optional services: A set of services which the tool may optionally make use of. This set may be quite large, depending on the tool.

A tool then encodes the information about its required, provided and optional services in a standard format and publishes this information. This enables a builder ment, used for assembling a software engineering environ-ment, to inspect the required and optional services of each component and match these with the provided services of other components.

Consider a simple example of assembling four tool com-ponents: a software repository, maintaining all software ar-tifacts; a repository browser, which may be thought of as an application similar to Microsoft’s Windows Explorer, offer-ing a view of, and a set of actions on, the files and folders in the repository; a text editor; and a compiler. The individ-ual components’ sets of services are shown in Table 1. As can be seen, all components except the repository browser provide a number of services, the repository browser com-ponent requires some services, and all comcom-ponents except the repository are able to make use of some optional ser-vices.

A possible “wiring” together of these components is shown in Figure 1. In this figure, each box represents a tool, a “socket” (cavity) a provided service, and a “plug” (protru-sion) a required or optional service. Plugs are connected to other components’ sockets, and more than one component may connect to the same socket. In the figure, plugs that correspond to required services are shown in a dark colour, while those that correspond to optional services are shown in a lighter colour. In the example, every socket is occu-pied by a plug from one or more other tool components, but this need not be the case as there may be some provided services which no other tools may be able to utilize. For example, the editor provides a service to position the cursor on a specific line of the text file, which the compiler utilizes whenever it finds an error in the input file passed to it by the editor for compilation. Suppose the compiler did not have the ability of utilizing such a service, then the editor’s corre-sponding service socket would remain unoccupied. On the other hand, if the editor were to lack this service and the compiler would require it, the configuration would be in-valid and the compiler would not be able to operate. There-fore it is important that only essential services are flagged as required and all other utilized services as optional.

More formally, we can say that a component

is charac-terized by the ordered set of properties . ,

(4)

a b c d e c Repository Compiler a a b b a c d e b Editor Repository Browser

Figure 1. Example of “wiring” four tool com-ponents together

and , in turn, are sets representing the component’s

pro-vided, required, and optional services, respectively. These sets are disjoint and can be empty. Let a given service be denoted as, and the cardinality of the union of , and be

, then a component’s properties are:

! "!#%$& !#(')!#('*+ ! ,-$. ,'!,'*+ ! /0$1 where2436573 .

Let 8 be a configuration consisting of the set of

com-ponents +! !"

/9$ , and let the sets of services , , and characterizing a given component

be denoted

as ,:, and ;, respectively. Then the properties of8 , < , is the ordered set consisting of the unions of the sets of

services , and of components

+! / , i.e.: < = 4> > ! ! > / $& > :+> ! ! > ?/0$& @ > ;+> ! ! > :/9$

Configuration 8 is said to be valid iff BA= , i.e.

all required services are matched by the provided services. Configuration 8 is said to be complete iff CAD , i.e.

all optional services are matched by the provided services. In a valid configuration, every component works, while in a complete configuration, every provided service of every component works.

In addition to these inter-component dependencies, there also exist intra-component dependencies. That is, some of the provided services of a component may only be available if certain of the component’s required and/or optional ser-vices are available. A dependency between serser-vices may be expressed as an ordered pairEGF&H , whereE is a provided

service (the dependent), and H is a set of services thatE

depends on (the depended). Services inH are restricted to

elements of the component’s property sets and . The

dependencies of a given component

are represented as a set of such pairs, denoted asHI . As dependencies that

only involve required depended services are always

satis-fied in valid configurations, they do not need to be explicitly represented. Dependencies with an empty depended set are always satisfied and need not be represented either.

As an example, given a component

with properties

J K ) !L$& !M$& NO$ , dependencies of this

component might be H 7!L:FPN+)O$&$ . That is,

pro-vided serviceL depends on the availability of optional

ser-vices N and O . Knowledge of such dependencies is used

when determining which functions of a component should be enabled or disabled in a given configuration.

To enable correct matching of required and provided ser-vices, a controlled vocabulary of service descriptors has to be used. Besides avoiding homonyms and synonyms, it should also distinguish between different versions of a ser-vice. To return to the earlier example of the ER diagrammer and SQL code generator tools, different versions of these tools may produce output and require input in different for-mats. If the diagrammer produces ER diagrams in a version not supported by the code generator, the two tools would not be pluggable. Therefore, a service is identified by a descrip-tor that includes the service name, data format, and service version. Given this information, different tools’ required and provided services can be correctly matched.

4. Implementation

To put the above ideas into practice we have designed and partly implemented a number of tool components and service representations. Our prototypes are implemented in Java and are based on the JavaBeans [7] component model. To allow interoperation of tool components we utilize the JavaBeans Activation Framework (JAF) [3], a typing and registry technology for JavaBeans.

This implementation builds on our earlier work from the ICCS project [2]. An outcome of that project was a networked software configuration management repository which allows distributed team members to share the objects of their development work. This repository is also central to our current work on component-based software engineering environments. To simplify the expositions that follow, how-ever, we have adopted another, file system-based repository for integration with other tool components.

4.1. Tool integration mechanism

Every one of our software tool components is imple-mented as an individual Java Bean. Using the JavaBeans Activation Framework, the capabilities (i.e. the provided services) of different tools are expressed as the available commands on a given type of object. The JAF’s default ob-ject typing mechanism is based on MIME types, although user-defined typing schemes can be employed. The JAF also provides a service, using a “command map” object, to

(5)

discover the available operations on a given object, and to instantiate a Java Bean that can perform the operation. Us-ing this framework, tool components do not require previ-ous knowledge of each other as long as they employ JAF services and instantiate relevant JAF objects. Components rendezvous through these JAF objects that encapsulate ac-cess to the data. The specific details of the JAF mechanisms are described in [3].

Returning to our example of the four software tool com-ponents, we can examine what is required to integrate them. We first implemented the components separately from each other and without interoperation capability, i.e. neither us-ing direct method invocations, nor usus-ing the JAF. We then added code to utilize the JAF to find other components and the services they provide, and to instantiate such component objects. Before going into detail about the code modifica-tions, however, we first need to describe the object typing that is essential to this framework. The information that we needed to encode included information on the types of ob-jects supported in our system and the possible operations available for each type. Object types are listed in a MIME type registry file on the user’s computer, such as the follow-ing registry for Java source code files that is based on file name extensions:

type=text/java desc="Java Source Code" \ exts="java,jav"

In this case, files with extension java or jav are identified as Java source code for which the MIME type text/javais assigned. The available operations for this object type are listed in another registry, which also identi-fies the Java Bean that can perform the named operation:

text/java; ; \

x-java-compile=mo.umac.iccs.tools.JavaCompiler; \ x-java-view=mo.umac.iccs.tools.SimpleEditor; \ x-java-edit=mo.umac.iccs.tools.SimpleEditor; \ x-java-print=mo.umac.iccs.tools.TextPrinter

This entry shows that four operations have been defined for files of typetext/java: compile, view, edit and print. The Java Beans performing these operations all belong to the packagemo.umac.iccs.tools, and a given Java Bean may be able to perform more than one operation, as in the case of theSimpleEditorBean. Other object types be-sidestext/javahave similar entries in the two registries. The required modifications to our program code were moderate, depending on the role played by the component within the overall system. Some components assume the role of activator, some are activated components, and some are both. The repository browser, for example, is a pure activator as it only utilizes services from other components and does not provide any of its own services. The reposi-tory on the other hand is a pure activated component, as it

only offers provided services and does not utilize any ser-vices from other components. Finally, the editor and com-piler components are both activator and activated at differ-ent times.

Activator components, which in a conventional applica-tion would directly instantiate other classes and invoke their methods, need to do several more things when using the JAF. Suppose such a component has a data object which it wishes to pass to another component for processing. It first needs to look up the type of this object using a JAF ser-vice that determines the MIME type of a given object. Next it needs to discover the available commands on this type of object. After choosing the desired command, it looks up the corresponding Java class that implements this command. It also needs to enable access to the data object by instantiat-ing a suitable data source class that performs low-level data access, and then using this data source class for instantiat-ing a suitable data handler class that provides a high-level interface to data from many different sources and in many different formats. Now, using the data handler, our compo-nent can instantiate the Java Bean whose class it discovered earlier. Figure 2 shows a code fragment illustrating this.

For activated components the situation is simpler. Ev-ery such invocable Java Bean needs to implement the JAF interface CommandObject and to provide a method setCommandContextthat receives a command verb and a data handler to the data object on which the specified com-mand should be performed. This method then typically in-vokes other internal methods to perform the command. In addition, the component has to access data through the data handler. This requires only very little modification to exist-ing code, as the data handler provides the component with both input and output streams to access the data, which are common data access mechanisms.

The completed application is shown in Figure 3. A menu frame on the top provides access to tools, and the repository browser below it is brought up from its Tools menu. The repository browser displays contents of the repository, an-other (non-visible) component. When right-clicking an item in the browser window, a popup menu of available actions is displayed, such as the one in the figure. In the example, a file has been selected for edit, and the corresponding editor component (on the right) is launched with the contents of the file, using the mechanism described above.

4.2. Builder environment

In our current prototype implementation, components are manually assembled. However, we plan to create a builder environment that can automate this task. Besides as-sisting the user in assembling components, a builder would also aid the user in producing valid configurations, some-thing which the JAF alone or existing builder tools are not

(6)

// Look up the MIME type of this file

// (‘fileName’ is the name of a file whose data we want to // pass to another component for processing)

MimetypesFileTypeMap mftMap = new MimetypesFileTypeMap(); String mimeType = mftMap.getContentType(fileName);

// Find out the set of commands for this object MailcapCommandMap mcMap = new MailcapCommandMap();

CommandInfo[] commandInfo = mcMap.getPreferredCommands(mimeType);

// Now select the command that we want to perform, say the i’th one // (this is mostly selected by the user through a popup or similar) String command = commandInfo[i].getCommandName();

// Get a data source and a data handler to handle the file File file = new File(fileName);

DataSource ds = new FileDataSource(file); DataHandler dh = new DataHandler(ds);

// Instantiate a Bean to process the data in the file Object cmdBean = dh.getBean(dh.getCommand(command));

Figure 2. Code fragment for passing a data object to another component

able to do. The JAF only assists in finding a suitable content handler for a certain operation on an object. It has no notion of different kinds of services (provided, required, optional) and does not validate a given configuration of components. For example, we purposely added invalid information into the object types registry, indicating a print service for Java source code files, however, the named JavaBeans compo-nent does not exist. This is not detected by the JAF, and so theprintaction is (wrongly) shown in the Actions popup menu as an available action on Java files. A builder en-vironment should therefore extend the functionality offered by the JAF with a suitable support for assembling valid soft-ware engineering environments. This builder will have in-formation about all available components, their properties and dependencies, and use this to assist the user in assem-bling valid software engineering environments. For exam-ple, when the user selects a component with a certain set of required services, the builder should search for other com-ponents that can provide these required services and offer a choice for the user to select. It should also allow the “wiring”, as shown in the earlier example, of optional ser-vices, again pointing out to the user possible and valid in-terconnections between components.

Some of the information required by a builder exists in the object types registry, however this corresponds only to the provided services. Information on required and op-tional services is not included, neither is the detailed ser-vice descriptor information (cf. section 3). In order to provide this information, an auxiliary class, implementing

the BeanInfo interface and named appropriately, should be created for each JavaBeans component. For example, theSimpleEditorclass’s service properties should be en-coded in the SimpleEditorBeanInfoclass. A builder can then examine all BeanInfo classes, extract the relevant information using the Java introspection mechanism, and determine any possible component connections and also any required but unavailable services.

5. Legacy Tool Integration

The method of tool integration described in the previ-ous section assumes that all tools are implemented as JAF-aware components. However, a large number of tools ex-ist that were not designed to support this framework, and many were not even implemented in Java. While it would be desirable for all tools to be JAF-aware, this is not realistic given the large number of legacy tools, the different imple-mentation languages and not least of all the lack of access to commercial tools’ source code. Therefore, an implementa-tion of the component model should support the integraimplementa-tion of such legacy tools into the framework.

Generally, in our implementation a tool component needs to fulfil three conditions: (1) it needs to be imple-mented as a Java Bean; (2) it needs to invoke other tool com-ponents using the JavaBeans Activation Framework; and (3) it needs to advertise its service properties and dependencies using aBeanInfoclass. Any tool that does not fulfil all of these conditions is considered a legacy tool.

(7)

Figure 3. Sample of several tool components assembled

The integration of such legacy tools can be enabled by implementing representatives, i.e. Java Beans that fulfil the above conditions and that represent legacy tools within the component model. A representative provides map-pings between services in the component model and the legacy tool’s corresponding functionality. For example, tak-ing thevi editor as a legacy tool, it may provide a num-ber of services, such as edit-text, edit-text-file, view-text-file, etc. These services are mapped to cor-responding invocations of the tool, such as in this casevi, vi %s,view %s, etc. (where%sis a string placeholder for a file name).

Two main categories of legacy software tools can be dis-tinguished: those implemented in Java, and those imple-mented in other languages. Depending on this distinction, we provide two different types of representatives: for the former category we use adapters and for the latter we use wrappers.

An adapter is a small software component that encapsu-lates access to a non-JAF-aware Java component. It adver-tises itself as providing the services that the Java component encapsulated by it supports. Upon activation by another activator component, the adapter instantiates the Java tool component and invokes the method on the tool that corre-sponds to the command verb it received from the activator. Since Java tools expose their public methods, this approach enables not only the instantiation, but also the invocation of methods during the lifetime of the tool object.

Wrappers, while fulfilling a similar role as adapters, have to interact with external software tools through an exter-nal process, essentially by invoking the tool through the

exec() method provided by java.lang.Runtime. If those tools provide their own APIs, it is possible for a wrapper to provide access to significant tool functionality through that API. However, in the absence of an API, a wrapper will only be able to invoke a tool and will have no possibility of interacting with it during its lifetime.

A builder environment should aid the integration of legacy tools into the JAF framework by maintaining code skeletons for both adapters and wrappers, and obtaining the necessary invocation and mapping information of legacy tools from the user. This information would include class names and method signatures (in the case of Java classes) or program names and command line options (in the case of external tools), corresponding service descriptors and ser-vice type, and other information required to provide a suit-able runtime environment, such as required temporary files, environment variables, etc. In simple cases, a representa-tive could then be automatically generated, using the appro-priate code skeleton and the user-supplied information. In slightly more complex cases, the code skeleton may need to be augmented with additional code by the user. However, in some complex cases, the entire representative will have to be manually implemented.

An example of using an adapter and a wrapper is shown in Figure 4. Here the repository is assumed to be a non-JAF-aware Java component, and so an adapter encapsulates access to it. To the rest of the system the repository ap-pears like an ordinary component, however internally the adapter uses a different mechanism for interacting with it (symbolized by the round connectors between adapter and repository). The compiler component, on the other hand,

(8)

a b c d e a c d e b Editor Repository Browser a b Compiler c b a Repository

Figure 4. Integration of tool components us-ing an adapter and a wrapper

is assumed to be an external tool and is consequently en-capsulated in a wrapper. Again, through the wrapper the compiler provides the common interface to the rest of the system, however internally communication between wrap-per and compiler is by means of an external invocation.

6. Conclusions

This paper has explored customizability requirements of software engineering environments for flexible distributed software teams consisting of contracted software engineers. We have defined a component model and implemented sev-eral prototype tool components using the JavaBeans Activa-tion Framework (JAF). We have also outlined mechanisms for the integration of non-JAF-aware and non-Java legacy tools.

Our experience using the JAF has shown that it is rel-atively easy to modify a tool component to become JAF-aware, and that the resultant tools can interoperate with-out any knowledge of each other. However, we found the JAF mechanism to be somewhat crude, as tool activation is achieved by means of a component invocation, i.e. a new in-stance is generated at every activation and there is no mes-sage passing mechanism to previously invoked tools. We are currently devising our own extensions to the JAF mech-anisms to overcome this shortcoming, and are considering the use of special message objects to be exchanged between components through each other’s data handlers.

We also need to create a standard catalog of service and message names with well-defined semantics. Currently, us-ing the JAF mechanism, a command verb identifies a com-ponent’s provided services, and it is possible that naming conflicts may arise. A standardized catalog, enforced by a builder environment, would solve this problem.

Still much work is required to achieve the degree of

tool standardization and interoperation that will enable highly customizable software engineering environments. The ideas presented in this paper will hopefully be one step in that direction.

Acknowledgments

This work was sponsored in part by the University of Macau Research Committee under research grants RC004(96/97) and RC063(96/97). The support is gratefully acknowledged.

Thanks are also due to Tou Chi Pio (Bryan), our local Java expert, who implemented the ICCS repository.

Any trademarks appearing in this paper are hereby ac-knowledged.

References

[1] S. Benford, J. Bowers, L. E. Fahl´en, J. Mariani, and T. Rod-den. Supporting cooperative work in virtual environments.

The Computer Journal, 37(8):653–668, 1994.

[2] R. P. Biuk-Aghai. The ICCS project: Current status and future directions. Research Report SE-1998-01, Faculty of Science and Technology, University of Macau, Apr.

1998. http://hyperg.sftw.umac.mo/robert/

publications/ICCS-project.ps.gz.

[3] B. Calder and B. Shannon. JavaBeansTMActivation Frame-work Specification Version 1.0. Sun Microsystems, Mar. 16,

1998.

[4] A. Dix. Challenges and perspectives for cooperative work on the Web. In Proc. ERCIM Workshop on CSCW and the

Web, Sankt Augustin, Germany, 1996.

[5] J. Dominigue and P. Mulholland. Fostering debugging communities on the Web. Communications of the ACM, 40(4):65–71, Apr. 1997.

[6] B. A. Farshchian and M. Divitini. ICE: A highly tailorable system for building collaboration spaces

on the WWW. In ACM GROUP‘97 Workshop on

Tailorable Groupware: Issues, Methods, and Architec-tures, Phoenix, Arizona, USA, Nov. 16, 1997. http: //www.ifi.uib.no/staff/anders/research/ group97/wspapers/baf-divitini.ps.

[7] G. Hamilton, editor. Sun Microsystems JavaBeansTM

. Sun Microsystems, July 24, 1997.

[8] D. Heimbigner and A. Wolf. Managing distributed software configuration and deployment. ACM Software Engineering

Notes, 22(5):52–53, Sept. 1997.

[9] J. Perpich, D. Perry, A. Porter, L. Votta, and M. Wade. Any-where, anytime code inspections: Using the Web to remove inspection bottlenecks in large-scale software development. In Proc. 1997 International Conference on Software

Engi-neering, pages 13–21, May 17–23, 1997.

[10] O. Stiemerling and A. B. Cremers. Tailorable component architectures for CSCW-systems. In Proc. 6th Euromicro

Workshop on Parallel and Distributed Programming, pages

References

Related documents

Different countries, different types of incubators (profit or no-profit oriented, oriented toward specific industrial branch or with general orientation).. has different

(1872–2016) of the floodplain vegetation of a segment of the heavily regulated upper Rhine River to different static approaches for the es- timation of its PNV a) a statistical

At Alkermes Contract Pharma Services we offer a complete range of analytical capabilities to support your requirements – be that technology transfer, scale- up, clinical

Our study found that RBP-4 levels in lean PCOS patients did not show any association with insulin resistance, this result was similar with previous study, showed higher RBP-4

Employers were also asked why they decided to provide the benefit, any barriers they experienced to adding the benefit, what benefits they receive by providing the coverage,

In support of this argument, the Appellants submit that because neither home is strata titled that the structures constructed on the sites are caught under section 2(1)(a) of

The standard practice is to fit the computed total discharge current waveform using four model parameters representing the mass swept-up factor fm, the plasma current factor fc

In modern free verse the very typographical arrangement of words in lines produces emphasis, just as regular rhythm and rhyme produce emphasis in regular verse. There is such a