Giter Club home page Giter Club logo

jolie's Introduction

Welcome to the Jolie open source project!

What's Jolie?

Jolie is a service-oriented programming language, designed to offer native abstractions for the development of microservices. See our website for more information and installation instructions.

Have you made something in or for Jolie? Please submit it to our awesome Jolie list!

Documentation ๐Ÿ“”

See https://docs.jolie-lang.org/ for documentation on how to program with Jolie.

For documentation on the interpreter, see https://github.com/jolie/jolie/wiki/Interpreter-documentation.

Roadmap ๐Ÿ“ˆ

You can check our roadmap to see what's staged for the next release.

Contributing ๐Ÿ’ป

Jolie is an open source project based on community effort. Contributions and constructive discussions are always welcome, and we encourage you to join us! There are many ways in which you can contribute, including coding, improving our documentation, helping out with newcomers, or even event organisation.

Interested in contributing? Please check our contribution and organisation guide.

All interactions regarding the Jolie open source project are expected to follow the code of conduct.

Our contributors ๐Ÿ‘

Thank you to all our contributors!

Code status ๐Ÿง

Java CI

Get in touch ๐Ÿ‘‹

Discussions can take place over different media.

Discord

Join our Discord server

Join our Discord server.

jolie's People

Contributors

abjunior92 avatar aff2bfe avatar bergarsimonsen avatar bmaschio avatar braza501 avatar d4vidh4mm3r avatar danthrane avatar dependabot[bot] avatar eferos93 avatar emilovcina avatar ezbob avatar fmontesi avatar kicito avatar klag avatar lgtm-migrator avatar lsafina avatar lucat1 avatar maje419 avatar mmontesi avatar mwallnoefer avatar simonlarsen avatar supermauro1966 avatar thesave avatar tiggles avatar vickimixen avatar xpicox avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jolie's Issues

HTTP GWT-RPC

During writing a unit test for GWT-RPC I got this exception:

Exception in thread "Thread-46" com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException: This application is out of date, please click the refresh button on your browser. ( Malformed or old RPC message received - expecting version between 5 and 7 )
at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.prepareToRead(ServerSerializationStreamReader.java:418)
at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:237)
at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:167)
at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:124)
at jolie.net.HttpProtocol.parseGWTRPC(HttpProtocol.java:893)
at jolie.net.HttpProtocol.recv_parseMessage(HttpProtocol.java:1105)
at jolie.net.HttpProtocol.recv_internal(HttpProtocol.java:1243)
at jolie.net.http.HttpUtils.recv(HttpUtils.java:129)
at jolie.net.HttpProtocol.recv(HttpProtocol.java:1334)
at jolie.net.SocketCommChannel.recvImpl(SocketCommChannel.java:95)
at jolie.net.CommChannel.recv(CommChannel.java:194)
at jolie.net.CommCore$CommChannelHandlerRunnable.run(CommCore.java:601)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)

Handling date and time formats

@jolie/developers
#71

Hi all I was wandering what you thing about the possibility of adding a Date native type, in my opinion it would be useful in handling DB interaction in particular in the case of not SQL DB .
What do you think

Balint

API refactoring regarding boolean parameters

Before releasing a new major release, we should transform all int parameters which are intended as boolean. I know that such a change breaks compatibility, but let us discuss it here. For instance in the Database service we have:

type ConnectionInfo:void {
.port?:int
.toUpperCase?:bool
.username:string
.host:string
.checkConnection?:int < should become bool
.toLowerCase?:bool
.driver:string
.attributes?:string
.password:string
.database:string
}

SchedulerService

This time I had a look on the source of our Java Services. The SchedulerService (javaServices/coreJavaServices/src/joliex/scheduler/SchedulerService.java) seems weird to me, since it contains plenty of commented code. I wonder if we could get rid of it, since this looks not very professional!

Improve the Sublime plugin and its visibility

@thesave I use the Jolie plugin for Sublime Linter regularly now and I can't live without it. But, installing it is a bit quirky (has hardcoded directories) and the Jolie websites does it no justice (it's our mainly supported editor but that's not very visible).

@jolie/developers Have you tried it? Your life will change. I helped Saverio refactor it a bit to use libjolie and he was kind enough to do the coding, so now so you get online errors in the editor about what the jolie interpreter may not like (wrong operation names, wrong port names, missing interfaces, etc.). Since we use libjolie, this now means that improving the SemanticVerifier or OLParser in libjolie automatically also improved Sublime Jolie!

I mean, look at how nice it is:

Sublime Jolie Linter

We must fix this!

@thesave Can you tell us what we lack to make it easier to install for any generic Jolie installation?

After we fix this, the next item should probably be to make that underlining a bit more precise and to output more helpful messages from libjolie.

Embedded services should be able to automatically load all their libraries in lib folder

When a service is embedded in a parent service, it is not able to load the libraries contained in its lib folder.

It is possible to override this problem by loading libraries inside the embedded code with a loadLibrary@Runtime invocation but it is a very bad solution. The developer indeed is forced to change his programming style depending on the fact that the service will be embedded or not (and we must avoid it).

Invalid encoding name ""UTF-8""

If we create a jolie interface starting from the wsdl of the service described at #42 and we try to use the following client for invoking that web service, we will get the error:

Invalid encoding name ""UTF-8""

Client


include "console.iol"
include "myWsdlInterface.iol"

main {
request.message = "ciao";
test@MyPortServicePort( request )( response );
println@Console( response.message )()
}

where myWsdlInterface.iol is the interface generated with the wsdl2jolie tool starting from the wsdl of #42

When doing a response on client request can't add custom headers

Initially I tried to enable CORS so that there were a need for me to response with additional headers on client request.

I tried this way as it's said in documentation.

inputPort Server {
Location: "socket://localhost:5000/"
Protocol: http {
.method = "get";
.addHeader.header[0] <<"X" {.value="Y"};
.statusCode -> statusCode
}
Interfaces: SumInterface
}

So, I looked through the sourcecode on gihub and found out that the implementation of send_appendResponseHeaders don't include custom headers for response that makes impossible to make CORS request from browser.

see here

private void send_appendResponseHeaders( CommMessage message, StringBuilder headerBuilder )

However, there is one line of code for request:

send_appendHeader( headerBuilder );

So, probably it's a BUG to fix.

reflection.ol test failing

[reflection.ol] Request-Response process for test threw an undeclared fault for that operation (InvocationFault), throwing TypeMismatch

I got it on various machines and also after a complete rebuild. For now I disabled it since it prevented the execution of the other unit tests.

Internal services

Hi all,

I'm reposting this from my original e-mail to the mailing list for Jolie 1.2. I've postponed this feature due to lack of discussion, so I'd like to rekindle that here.

Motivation

Right now doing procedural programming in Jolie is a pain, as we do not support local variables in defined procedures. This is intentionally painful, as using procedures too much can make it hard to switch to a distributed implementation based on communications later on.

A procedure basically acts as a request-response invocation: we call it, and then we wait until it's done. Therefore we usually implement recursive algorithms by having a service call itself on one of its operations (e.g., see here). This is a bit cumbersome sometimes and promotes bad design (algorithms should be implemented in a separate service most of the time, but creating separate services is a bother sometimes). So we need syntax sugar! All the elements are basically there, we only need to find a nice syntax and do some plumbing in the interpreter to make it work by using the mechanisms we already have. So what I would really like to have is the possibility of defining lightweight "internal" services inside of a Jolie program.

Requirements

  • Internal services should be easy to code, as in quicker than coding a fully-fledged Jolie service. We want syntax sugar. The whole reason for introducing them is to avoid the bother of defining a separate Jolie file to embed, with its interface and ports everything.
  • We should also be able to have many internal services with different names, so that the programmer is left free to split operations as she sees fit.
  • Finally, internal services should have the same lifecycle as a normal embedded service.

Initial Proposal

We introduce a keyword, e.g., "service", to define internal services that works like this:

interface SrvIface {
OneWay: op(void)
RequestResponse: op2(T)(T2)
}

service Srv {
Interfaces: SrvIface
Code: {
    [ op1() ] { ... }
    [ op2(x)(y) { ... } ]
}
}

Srv would work as an embedded service, so this would get compiled to:

outputPort Srv {
Interfaces: SrvIface
}

embedded {
Jolie: *internal reference to the code of the Srv* in Srv
}

So that now we can use Srv inside of our Jolie program:

main {
    op2@Srv( x )( y )
}

Discussion points

  • Should Srv inherit anything from the enclosing service? Some examples follow.
  • Can Srv use the output ports of the main service?
  • Which state should the processes created by Srv access? Should they start with a clean state (no variables instantiated), a copy of the state of the init procedure from the main service (as do all processes started in the main service), or a copy of the state of the caller process from the main service that invokes the operation in Srv?
  • Syntax: here's an alternative below. You may have other ideas, please share.
service Srv implements SrvIface {
    [ op1() ] { ... }
    [ op2(x)(y) { ... } ]
}

About the first three points, if we want to stay on the safe side we may start by using a clean slate (no variables instantiated at all, the internal service is completely independent), which is what I like best for now. We may also actually want internal services to have an init procedure like regular services:

service Srv {
Interfaces: SrvIface
init {
    ...
}
main {
    [ op1() ] { ... }
    [ op2(x)(y) { ... } ]
}
}

generateDocumentation.ol does not work

If I try to run it on the website server to re-generate the docs, it prints:

INFO: [generateDocumentation.ol] Output message TypeMismatch (getFiles@Self): Invalid native type for node #Message: expected STRING, found void

Apparently we're doing something wrong with the paths. Saverio, can you look into this?

Database connection pools

I would like to switch to something standard for handling our database connections in DatabaseService (right now, we handle them manually), as the service needs improvements and I don't see a reason to reinvent the wheel. I had a look around but I wonder if somebody here has experience/knows what they're using in other major Java frameworks? Then we could simply go with that.

local location definition

I think it is very important to specify different local location instead of having one single reference as "local" is.

consider the case of 3 services, where A -> B, B -> C, C-> A.
If I want to deploy this architecture in a distributed way, it is very easy to manage locations outside the service code: we can use config.iol files for specifying the different locations and configure the pointers to all the services.

But if I would like to reduce the usage of ports and programming in-memory communication, these services required to be modified in the behaviour because they are not connected vertically. It is a "2D" architecture :-). Thus everywhere I put my embedder, some "local" locations created by it must be communicated to some services.

On the contrary, If we have local channel specifications we could do it in this very simple way:

  • I create another microservice D which embeds A, B and C
  • I define all the locations as: local://id_loc_service_A, local://id_loc_service_B, local://id_loc_service_C

In this way it is possible to manipulate deployment of local location and external locations from the outside without affecting the codes of A,B and C. This is a key point for microservice architecture management.

The structure of local locations, I suggest:

local://my_id

Maybe we could adopt a tuple space (http://en.wikipedia.org/wiki/Tuple_space) for getting this result. In this case the tuple space should be unique for each Jolie JVM. Thus I could have nested embedded services, but all of the services which are in the same JVM use the same tuple space for communicating through local channels.

Cannot rethrow an unknown fault

In this simple code I need to rethrow a fault in the default handler. The problem is that I statically don't know the fault, thus I need to pass a variable to the throw primitive but the scanner accepts only IDs

include "console.iol"

main {
scope( a ) {
install( default => println@Console( "error " + a.default )();
throw( a.default )
);
throw( MyError )
}

}

I like the idea to have ID tokens for the throw primitive and not variables but maybe we could add primitive

throw( default )
and
throw( default, a.( a.default ))

for just raising the same fault to the upper scope.

what do you think?

JolieDoc and code comments

Our generated API documentation (http://docs.jolie-lang.org) loses all (helpful) comments written in the various headers. Not sure if we can fix it, since they pass the Jolie parser which correctly ignores comments before being converted into the doc format. Did I get this right?

Importing multiple copies of the same service

Something I don't like about our current implementation of the standard library is that it is difficult to use multiple copies of the same service.

For example, if one wants to use one instance of Database, we simply need to do:

include "database.iol"

main { ... query@Database(x)(y) ... }

This works very nicely for one database (include and go!), but what if I need to connect to two different databases? I cannot include database.iol twice, since that will define all interfaces and outputport in database.iol twice, causing an error. A user is thus forced to actually delve into our code in database.iol and find out that another copy can be created like this:

include "database.iol"

outputPort Database2 { Interfaces: DatabaseInterface }

embedded { Java: "joliex.db.DatabaseService" in Database2 }

main { ... query@Database(x)(y) ... query@Database2(r)(s) ... }

What bugs me in particular is that we need to know the string "joliex.db.DatabaseService", which I may want to change in the future, and that I need two constructs (outputPort and embedded), but maybe it's just me. Is it bugging somebody else or do you find our current way of doing things fine?

Missing mutex in jolie.net.CommCore

Exception in thread "testClient.ol-testClient.ol-SelectorThread" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1042)
at jolie.net.CommCore$SelectorThread.run(CommCore.java:865)

Invalid constant definition via "-C" parameter under Windows

Setting constants via the relative option jolie -C c=42 program.ol returns the error:

Invalid constant definition, reason: expected = after constant identifier Server_location, found token type EOF

I think it should not be a difficult fix but unfortunately I do not have the time to fix it. Can someone look into this?

Use the Files class in FileService

FileService (file.iol) implements operations that are now provided by the Files class since Java 7.

Whoever wants to take a shot at replacing our custom implementations with the standard ones from Files, feel welcome to give it a try. Please remember to use the java8 branch, since master is still targeted at Java 6.

Apache HData

@jolie/developers
HI All
In the enterprise side of things one of the buzz words is big data and vertical DBase, so i thought how can we use jolie to work with big data, are micro-services suited for this task. So I started wandering if there was an open version of vertical DBase. And I found HData of Apache. I was wandering if anyone wants to help me with a possible implementation of a Jolie service
Regards
Balint

Jolie on Windows - ant test

On Windows during testing SSL I sporadically encountered:

 [exec] Nov 05, 2015 6:29:52 PM jolie.Interpreter logSevere
 [exec] SCHWERWIEGEND: [http_post.ol] Request-Response process for test threw an undeclared fault for that operation (IOException), throwing TypeMismatch
 [exec] Nov 05, 2015 6:29:52 PM jolie.Interpreter logWarning
 [exec] WARNUNG: [http_server.ol] java.nio.channels.ClosedChannelException
 [exec]     at java.nio.channels.spi.AbstractSelectableChannel.configureBlocking(Unknown Source)
 [exec]     at jolie.net.CommCore$SelectorThread.register(CommCore.java:886)

 [exec]     at jolie.net.CommCore.registerForSelection(CommCore.java:938)
 [exec]     at jolie.net.SelectableStreamingCommChannel._disposeForInputImpl(SelectableStreamingCommChannel.java:108)
 [exec]     at jolie.net.SelectableStreamingCommChannel.disposeForInputImpl(SelectableStreamingCommChannel.java:117)
 [exec]     at jolie.net.CommChannel.disposeForInput(CommChannel.java:303)
 [exec]     at jolie.net.CommCore$CommChannelHandlerRunnable.handleDirectMessage(CommCore.java:559)
 [exec]     at jolie.net.CommCore$CommChannelHandlerRunnable.handleMessage(CommCore.java:572)
 [exec]     at jolie.net.CommCore$CommChannelHandlerRunnable.run(CommCore.java:606)
 [exec]     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
 [exec]     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
 [exec]     at java.lang.Thread.run(Unknown Source)
 [exec]
 [exec] Nov 05, 2015 6:29:52 PM jolie.Interpreter logInfo
 [exec] INFORMATION: [http_post.ol] jolie.net.ChannelClosingException: [http] Remote host closed connection.
 [exec]     at jolie.net.http.HttpParser.parseRequest(HttpParser.java:176)
 [exec]     at jolie.net.http.HttpParser.parseMessageType(HttpParser.java:208)
 [exec]     at jolie.net.http.HttpParser.parse(HttpParser.java:358)
 [exec]     at jolie.net.HttpProtocol.recv_internal(HttpProtocol.java:1235)
 [exec]     at jolie.net.http.HttpUtils.recv(HttpUtils.java:129)
 [exec]     at jolie.net.HttpProtocol.recv(HttpProtocol.java:1350)
 [exec]     at jolie.net.SocketCommChannel.recvImpl(SocketCommChannel.java:95)
 [exec]     at jolie.net.CommChannel.recv(CommChannel.java:198)
 [exec]     at jolie.net.AbstractCommChannel$ResponseReceiver.run(AbstractCommChannel.java:227)
 [exec]     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
 [exec]     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
 [exec]     at java.lang.Thread.run(Unknown Source)
 [exec]
 [exec] Nov 05, 2015 6:29:52 PM jolie.Interpreter logSevere
 [exec] SCHWERWIEGEND: [http_server.ol] java.nio.channels.AsynchronousCloseException
 [exec]     at java.nio.channels.spi.AbstractInterruptibleChannel.end(Unknown Source)
 [exec]     at sun.nio.ch.SocketChannelImpl.write(Unknown Source)
 [exec]     at java.nio.channels.Channels.writeFullyImpl(Unknown Source)
 [exec]     at java.nio.channels.Channels.writeFully(Unknown Source)
 [exec]     at java.nio.channels.Channels.access$000(Unknown Source)
 [exec]     at java.nio.channels.Channels$1.write(Unknown Source)
 [exec]     at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
 [exec]     at java.io.BufferedOutputStream.flush(Unknown Source)
 [exec]     at jolie.net.SocketCommChannel.sendImpl(SocketCommChannel.java:112)
 [exec]     at jolie.net.SelectableStreamingCommChannel._send(SelectableStreamingCommChannel.java:101)
 [exec]     at jolie.net.SelectableStreamingCommChannel.send(SelectableStreamingCommChannel.java:78)
 [exec]     at jolie.net.CommCore$CommChannelHandlerRunnable.handleDirectMessage(CommCore.java:541)
 [exec]     at jolie.net.CommCore$CommChannelHandlerRunnable.handleMessage(CommCore.java:572)
 [exec]     at jolie.net.CommCore$CommChannelHandlerRunnable.run(CommCore.java:606)
 [exec]     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
 [exec]     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
 [exec]     at java.lang.Thread.run(Unknown Source)
 [exec]
 [exec] Nov 05, 2015 6:29:52 PM jolie.Interpreter logInfo
 [exec] INFORMATION: [test.ol] Internal server error
 [exec] http_post.ol...

Optional { nullProcess } for request-response inputs

Right now all request-response inputs require a body even though it's empty:

op( request )( response ) { nullProcess }

I'd like to be able to write this instead:

op( request )( response )

What do you think? This is in line with the recent modification to input choices.

Anybody up for this? It's a simple modification to OLParser.

Parametric procedures

Writing Jolie code can be error-prone sometimes due to code duplication.

I propose to solve this with parametric procedures:

define X(A, B)
{
    A = 3;
    B
}

Where A and B can be variable paths and code, for example this is an invocation:

p = 3;
X( p, { notify@Logger( "executed X" ) } )

p will have value 4 after that code, because these are stateless procedures: I am not proposing to introduce local variables (as I think that one should use a sub service to achieve that).

Parametric procedures work in principle as our current ones, so they may recur:

define X(A, B)
{
    A = 3;
    B;
    X( A, B )
}

This means that they are not a simple parsing expansion, but they will need an implementation as a concrete process in the OOIT (as our current definitions, since they can also recur).

As we have parameters, we probably want to type them now otherwise we may get runtime errors. For example the following is wrong and would get us into trouble:

define X( A )
{
   A = 3
}

In X, A is clearly a variable so if we pass a constant instead we are making a mistake:

X( 3 ) // this is an error because it will execute 3 = 3 inside of X

I propose the following types: path, val, and code.

define X( path A, val v, code C )
{
   A = v;
   C
}

Versioning

I'm moving the discussion about versioning in this issue, from #33 .

We're starting to see more and more needs for versioning services and libraries (see #33 and #24), as we may have hybrid architectures using microservices with different library versions.

As for the versioning scheme, I suggest something like they use in standard OSGi:

https://osgi.org/download/r6/osgi.core-6.0.0.pdf

(see pp. 35 and 36).

It seems useful to be able to refer to two different versions in the same program, so to create adaptors.

In-range for loops

In-range for loops

Problem

I'm getting sick of writing:

for( i = 0, i < #myarray, i++ ) { println@Console( myarray[i] )() }

Proposal

I propose:

for( element -> myarray ) { println@Console( element )() }

Where element would be an alias to myarray[index] at each iteration.

Discussion

Making element an alias to myarray[index] means that modifying the value of element inside of the loop would change the value of myarray[index]. In some language implementations, this is forbidden. However, it looks like this is pretty useful when manipulating structured documents, e.g., in XML. Opinions, @jolie/developers ?

Another problem

However, aliases do not work with anonymous arrays, which worries me. For example, if we had a syntax such as [ 1, 2, 3], this would not work:

for( element -> [1, 2, 3] ) { code }

because aliases can only target paths, not anonymous data structures.

Another solution

A safer (more future-proof) solution could be to have:

for( element : myarray ) { code }

Where element is copy of myarray[index] at every iteration, but that would be very slow (remember that each Jolie var potentially has a big tree underneath).

A compromise I dislike but seems like the best option for now is:

for( index : myarray ) { code }

where index is now instantiated from 0 to #myarray each time.

Can we get rid of gwt-dev.jar?

I'm wondering whether there is a smaller library covering the API subset we're using, as this one is quite huge and currently makes up for most of the size of a Jolie installation (!).

Anyone who'd like to look into this?

HTTPS does not work

Seems like the latest changes broke HTTPS, the working web server I had in website//jolie/jpsr/web/leonardo/leonardo.ol (launched by jolie/jpsr/main.ol) does not work anymore.

You can access it at https://localhost:8080/createUser.html

After we fix it let's make a test for https in the test suite before Jolie 1.3, looks like we break HTTPS now and then when we touch HTTP. It's pretty sensitive.

@mwallnoefer does it work for you?

Concurrent provide-until

Hi all,

Provide-until is already full of surprises. Here goes a crazy idea for dealing with a problem I encountered while using it.

Problem

Suppose you have a process that implements a chat room. It works like this: first you open the chat room; then, operations getHistory (for reading the content of the chat room) and postMessage (for posting a new message) are provided until operation closeChatRoom is called. We can elegantly encode this with the provide-until statement:

createChatRoom( room );
history = "";
provide
  [ getHistory()( history ) { nullProcess } ]
  [ postMessage( msg )() { history += msg + "\n" } ]
until
  [ closeChatRoom() ]

Nice, but inefficient: this is a typical readers/writers problem, but provide-until is currently always sequential. We should instead allow getHistory to be invoked in parallel, as it doesn't change our shared state. Differently, postMessage should indeed be sequential (no other threads should be changing the value of history while it is operating).

Solution 1 - Concurrent provide-until

We could introduce the option of telling provide-until which operations should be provided concurrently and which sequentially, for example:

provide!
  [ getHistory()( history ) { nullProcess } ]
provide*
  [ postMessage( msg )() { history += msg + "\n" } ]
until
  [ closeChatRoom() ]

The semantics of this would be:

  • all provide! operations are provided in parallel;
  • a provide* operation waits for all current invocations of provide! operations to terminate before executing, and likewise all other operations (including the provide!) cannot start until this operation invocation terminates;
  • until works as a provide* operation, but also terminates the statement.

Solution 2 - Programmable concurrency for provide-until

The solution above works for typical readers/writers but there may be scenarios where it doesn't suffice. In such cases, the programmer may want to specify a custom policy for telling Jolie when an operation should become available, maybe using internal links. Assume that all provide operations can go in parallel, then here is an example of how to realise the scenario (forgive the long syntax):

/* This block is called R,
    and is active only when no operation calls are being processed in block W */
provide[R requires W]
  [ getHistory()( history ) { nullProcess } ]

/* This block is called W,
    and is active only when no operation calls are being processed in blocks R and W */
provide[W requires R,W]   [ postMessage( msg )() { history += msg + "\n" } ]

// This blocks is active only when no other operation call is in progress in the other blocks
until
  [ closeChatRoom() ]

Solution 3 - Asynchronous Parallel

Another solution could be to use recursion. The current provide-until block can be simulated with recursion, for example the following

provide
  [ getHistory()( history ) { nullProcess } ]
  [ postMessage( msg )() { history += msg + "\n" } ]
until
  [ closeChatRoom() ]

can be implemented as:

define X {
  [ getHistory()( history ) { nullProcess } ] { X }
  [ postMessage( msg )() { history += msg + "\n" } ] { X }
  [ closeChatRoom() ]
}

This, however, fails if we want concurrency for getHistory:

define X {
  [ getHistory()( history ) { X | nullProcess } ]
  [ postMessage( msg )() { history += msg + "\n" } ] { X }
  [ closeChatRoom() ]
}

The reason is that X | nullProcess will make getHistory wait for the execution of X, which is not what we want. To get it right, we would need X to be able to proceed in parallel and not wait for it. Suppose to have this operator, || :

define X {
  [ getHistory()( history ) { X || nullProcess } ]
  [ postMessage( msg )() { history += msg + "\n" } ] { X }
  [ closeChatRoom() ]
}

Now X is executed and getHistory returns immediately, without waiting for X to terminate.
But wait, now postMessage can be active before some getHistory call is still computing. So we would also need a magical operator for postMessage to wait for all current parallel threads handling getHistory to terminate:

define X {
  [ getHistory()( history ) { X || nullProcess } ]
  [ postMessage( msg )() { wait_for_all_getHistory(); history += msg + "\n" } ] { X }
  [ closeChatRoom() ]
}

Conclusions

I hope you agree that provide-until can become more useful by powering it up a little. If not and you have an idea of how to do this with something we already have, I would be even happier because it would entail less development. ;-)
I showed some different potential solutions. Which to follow?
For now my preference is option 1 over 2 over 3. I dislike 3 as it is less declarative and simple, but we should always think about what we can do already before introducing something new, albeit convenient.
I find it really interesting that while provide-until right now (let's call it sequential provide-until) is just syntax sugar, it looks like that handling concurrency would make it a full-standing primitive in its own right.

A side note on execution modalities

It looks like having option 1 or 2 would effectively mix our three execution modalities (concurrent, sequential, and single) in a single primitive in a way that makes sense. I really like this, and maybe understanding this could pave the way for mixing execution modalities in the same service in a similar way, in the next-next-version.

spawn primitive does not work

This code is getting stuck when executing the spawn

include "console.iol"

main {
vec[0]="hello0";
vec[1]="hello1";
vec[2]="hello2";
println@Console("begin")();
spawn( i over #vec ) in result {
println@Console( vec[ i ] )()
};
println@Console("end")()

}

Use of cookies in HTTP

@jolie/developers
I am getting a bit stuck in the use of the cookies
Let me try to show you what I am trying to use

inputPort HTTPInput {
Protocol: http {
    .keepAlive = 0; // Do not keep connections open
    .debug = DebugHttp; 
    .debug.showContent = DebugHttpContent;
    .format -> format;
    .contentType -> mime;
    .cookies.sid  = "aaaaaaa";
    .default = "default"
}
Location: Location_Leonardo
Interfaces: HTTPInterface, ExampleInterface
}

I was expecting to set a cookies named "sid" and with value "aaaaaa"

SOAP message return carriage handling

@jolie/developers
Hi all
While i was working on issue number #38
I have noticed a problem while testing the SOAP call with soupUI with the following parameters

image

this is the error i get

AVVERTENZA: [main_test_wsdl.ol] Received message TypeMismatch (input operation G
etCitiesByCountry): Invalid native type for node #Message.parameters: expected VOID, found java.lang.String

that is given by the fact that the good old soapUi sends carriage return characters
Not even the

 .dropRootValue = true

has desired effect because it is applied only on the root node

I think this problem could be solved by implementing specification 2.11 End-of-Line Handling see link
http://www.w3.org/TR/REC-xml/#sec-line-ends

I will have a go with it tomorrow

What do you think about it

_b

Jolie Web Services acquired by NetBeans

Hi all

It is me again , being the usual pain , I was going to write a post on how to integrate Jolie Microservices in Java Program. So I thought to have a go with importing Jolie WebServices Using NetBeans 8.0.1
And this is how i went about it

  1. Create a simple Java Program
  2. Use the WebService Client to digest the WSDL generated by Jolie2WSDL
    image
  3. Drag the WebService operation testOperation into the java class this creates the following method
private static void testOperation(java.lang.String field1, java.lang.String field2, javax.xml.ws.Holder<java.lang.String> field3, javax.xml.ws.Holder<java.lang.String> field4) {
TestInterfaceSoapInputPortService service = new wsdl.namespacewsdl.TestInterfaceSoapInputPortService();
TestInterfaceSoapInputPort port = service.getTestInterfaceSoapInputPortServicePort();
port.testOperation(field1, field2, field3, field4);
}

From a Jolie interface that looks like this
type TestOperationRequest:void{
.field1: string
.field2: string
}

type TestOperationResponse:void{
.field3: string
.field4: string
}

interface TestInterface {
RequestResponse:
testOperation (TestOperationRequest)(TestOperationResponse)
}

Strait away i noticed some problems the signature of the java rapping method looks like not having response type

private static void testOperation(java.lang.String field1, java.lang.String field2, javax.xml.ws.Holder<java.lang.String> field3, javax.xml.ws.Holder<java.lang.String> field4)

Both input and output structures are flatten and passed as parameters of the method

  1. moving on i have tried use anyhow the generated method within my main method
javax.xml.ws.Holder<java.lang.String> field3 = new Holder<>();
    javax.xml.ws.Holder<java.lang.String> field4 = new Holder<>();
testOperation("a", "b", field3, field4);
  1. running the code I get

Exception in thread "main" com.sun.xml.internal.ws.streaming.XMLStreamReaderException: unexpected XML tag. expected: {nameSpaceWsdl.xsd}testOperationResponse but found: {null}testOperationResponse
at com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil.verifyTag(XMLStreamReaderUtil.java:203)
at com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil.verifyTag(XMLStreamReaderUtil.java:211)
at com.sun.xml.internal.ws.client.sei.ResponseBuilder$DocLit.readResponse(ResponseBuilder.java:538)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:110)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:135)
at com.sun.proxy.$Proxy31.testOperation(Unknown Source)
at wsdltest.WSDLTest.testOperation(WSDLTest.java:36)
at wsdltest.WSDLTest.main(WSDLTest.java:29)
Java Result: 1

Where the jolie port output is the following

http://www.w3.org/2001/XMLSchema-instance">SOAP-ENV:Bodyab/SOAP-ENV:Body/SOAP-ENV:Envelope

  1. with the option .dropRootValue = true; the situation does not change

Exception in thread "main" com.sun.xml.internal.ws.streaming.XMLStreamReaderException: unexpected XML tag. expected: {nameSpaceWsdl.xsd}testOperationResponse but found: {null}testOperationResponse
at com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil.verifyTag(XMLStreamReaderUtil.java:203)
at com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil.verifyTag(XMLStreamReaderUtil.java:211)
at com.sun.xml.internal.ws.client.sei.ResponseBuilder$DocLit.readResponse(ResponseBuilder.java:538)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:110)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:135)
at com.sun.proxy.$Proxy31.testOperation(Unknown Source)
at wsdltest.WSDLTest.testOperation(WSDLTest.java:36)
at wsdltest.WSDLTest.main(WSDLTest.java:29)
Java Result: 1

  1. Now to test if was my procedure to be wrong I tested it against a standard WebService the we all know http://www.webservicex.net/globalweather.asmx?WSDL

  2. now the generated method looks more like what i would expect

private static String getCitiesByCountry(java.lang.String countryName) {
net.webservicex.GlobalWeather service = new net.webservicex.GlobalWeather();
net.webservicex.GlobalWeatherSoap port = service.getGlobalWeatherSoap12();
return port.getCitiesByCountry(countryName);
}

that looks more like the wsdl definition

image

  1. if i call the method i get a list of data as I expect

I was wandering if any of you has experienced this before or it is a problem on how jolie answer to a soap call

I must say we had the same problem when trying a similar procedure under .NET, but at the time we thought to be a problem with .NET

Thank you
Balint

ParserException with comments (//) at the end of Jolie source files

I get a parse exception for the code below

include "console.iol"
main { println@Console( "hello world" )() } 
// this is a comment

It seems it regards comments at the end of Jolie source files.
I report below the error stack.

   jolie.InterpreterException: jolie.lang.parse.ParserException: /Users/thesave/Desktop/test.ol:3: error: Invalid token encountered. Found token type ERROR
    at jolie.Interpreter.buildOOIT(Interpreter.java:1270)
    at jolie.Interpreter.init(Interpreter.java:1037)
    at jolie.Interpreter.run(Interpreter.java:1112)
    at jolie.Jolie.main(Jolie.java:59)
Caused by: jolie.lang.parse.ParserException: /Users/thesave/Desktop/test.ol:3: error: Invalid token encountered. Found token type ERROR
    at jolie.lang.parse.AbstractParser.throwException(AbstractParser.java:197)
    at jolie.lang.parse.OLParser._parse(OLParser.java:221)
    at jolie.lang.parse.OLParser.parse(OLParser.java:183)
    at jolie.Interpreter.buildOOIT(Interpreter.java:1218)
    ... 3 more

Do you experience the same behaviour?

SOAP root values

Currently, SOAP does not transmit root values of messages.

This is however, only a WSDL 1.1 limitation, and prevents programs using, e.g., SODEP or HTTP to be ported to SOAP.

I think that we should transmit root values and leave this limitation only to when WSDL is used.
Please comment if you think that SOAP has this as an inherent protocol limitation or not.

type extender does not extend undefined values

If I try to extend the following interface with the Extender, the interpreter raises a NullPointerException. The problem is related to the undefined native type.
The same happens for type OpType: void { ? }

ex:
type OpType: undefined

interface MyInterface {
RequestResponse:
op( OpType )( OpType )
}

Timeouts for Solicit-Responses (Request-Response invocations)

Right now, a solicit-response invocation, for example

getUsers@Srv()( users )

can wait for a long time, and be interrupted by an IOException only when the underlying communication channel goes into a low-level timeout (e.g., a socket connection timeout).

It would be much nicer to be able to specify timeouts at the language level (note that this is not a problem for inputs since we can use input choices, with a particular input representing a timeout).

An option would be to have it as a configuration parameter, for example per operation (here I use the same .osc syntax as for http):

outputPort Srv {
Protocol: sodep { .osc.getUsers.timeout = 500 /* msecs */ }
}

I discussed this a bit with @klag and @thesave , they may have something to add (and I may have forgotten something ;-) ).

In case somebody is interested in working on this, a possible way is to change AbstractCommChannel.recvResponseFor to inspect the timeout parameter and use its value for waiting on the monitor on which the invoker waits for the response message. Feel free to ask here for more details.

ant test task for Windows

@thesave @mwallnoefer

I have recently added a test task to ant (so that we can run "ant test" on the command line) that runs the test suite. This was necessary to integrate our build system with Travis-CI (you can see the build status on our readme file now).

I have added a dummy target -test-windows for implementing the functionality on Windows (I've already put the check for the OS). Could you try to implement it by copying and modifying appropriately the target -test-unix ? The main differences are hopefully that we need to run cmd instead of sh and that we need to add the parameter suggested by @mwallnoefer at the end of issue #47 .

That way, we can stop running tests manually (jolie test.ol) and instead use ant test which does the right thing (tm) in the OS we are using at the moment.

What do you think?

SSL support

We should look into cleaning up SSLProtocol.java, see the bug in #39.

@mwallnoefer I have commented out your HTTPS tests for now, as they seem to block test.ol. Are you up for helping in cleaning SSLProtocol? There's even dead code in there. :-) I'd be glad to help.

@bmaschio Maybe you are also interested in this?

When a service is embedded by a parent in another path, File Service does not work

If you embed a service in a parent which is run in a different path of the embedder, the FileService always performs its operation starting from the path of the parent.

This is a problem because when you program a microservice you want to be responsible of the file system managed by that microservice, that is usually considered as all the folders and files contained in the microservice project folder.

SOAP requests coalesce into one if they share the same types

I report a bug found by Ivan Lanese.

Settings

We have the classic Calculator with this interface, types, and input port

type OpRequest:void {
    .x:int
    .y:int
}

type OpResponse: void {
    .result: int
}

interface CalculatorInterface {
RequestResponse:
    sum(OpRequest)(OpResponse),
    prod(OpRequest)(OpResponse)
}

inputPort In {
  Location: "socket://localhost:8000"
  Protocol: soap { 
    .wsdl="myWsdl.wsdl"; 
    .wsdl.port="InServicePort";
    .dropRootValue=true
    }
  Interfaces: CalculatorInterface
}

we created the companion wsdl following the procedure in the docs
(jolie2wsdl --portName In --portAddr http://localhost:8000 --o myWsdl.wsdl calculator.ol)

Issue

We used several tools to test the service, all giving the same issue. Below I report the images taken with RestInSoap.

The wsdl is correctly parsed to expose operations prod and sum, however when creating a new request e.g., for prod, RestInSoap (same behaviour for SoapUI) creates a request for sum. In general, it seems like one of the operations "coalesces" into the other.

screen shot 2015-10-01 at 08 48 40

Although we changed the name of the operation manually in the request --- in this case, from sum to prod ---, the Calculator gets a request for operation sum and returns a sumResponse.

screen shot 2015-10-01 at 08 49 13

If we differentiate the types of the two requests --- e.g., having distinct SumRequest, ProdRequest and SumResponse, ProdResponse --- everything works as expected (prod requests generate prodResponses and likewise for sum).

You can find the code in attachment (remove the .txt extension, damned GitHub extension restrictions)

Is it a issue or is it mandatory to have different types for each operation in SOAP?

calculator.iol.txt
common.iol.txt
myWsdl.wsdl.txt

Invoker Detection

It would be nice to be able to retrieve information about the invoker of an input port. This would be useful, e.g., for logging the IP address of an invoker.

In general, we have many types of communication channels, so there would be different types of information. For example, a socket could give an IP address, a local location would give the memory address of the invoker, and so on.

It looks to me, however, that this concept of "invoker information" makes sense for all channels. Hence we could augment all CommChannels with a new abstract method that we use to retrieve this information, and then each specific CommChannel implementation would have to provide its own implementation of the method (for sockets, local, unix sockets, bluetooth, etc.).

The question then becomes, how do we access this from the language? Any proposals?

Behavior difference Jolie2Wsdl

Hello everyone

During a Jolie training session i have notice a difference between the Jolie2Wsdl suggested use and the real command parser
This is the suggested use

jolie2wsdl [ -i include_file_path ] filename.ol soap_input_port_name
[ output_file ]

C:\Vincent Examples\TestVersion1.2.1\TestWSDL>jolie2wsdl main_test_wsdl.ol TestInterfaceSoapInputPort test.wsdl
Starting conversion...
null
apr 24, 2015 9:22:38 AM joliex.wsdl.WSDLDocCreator ConvertDocument
GRAVE: null
java.lang.NullPointerException
at java.io.FileOutputStream.(Unknown Source)
at java.io.FileOutputStream.(Unknown Source)
at java.io.FileWriter.(Unknown Source)
at joliex.wsdl.WSDLDocCreator.initWsdl(WSDLDocCreator.java:121)
at joliex.wsdl.WSDLDocCreator.ConvertDocument(WSDLDocCreator.java:138)
at joliex.wsdl.Jolie2Wsdl.main(Jolie2Wsdl.java:41)

Success: WSDL document generated!

but no file was generated

Instead using the following command form it seems to work fine
C:\Vincent Examples\TestVersion1.2.1\TestWSDL>jolie2wsdl --tns nameSpaceWsdl --
pN TestInterfaceSoapInputPort --addr http://localhost:10000 --oF TestService.wsd
l main_test_wsdl.ol

This is due by the following command parser implementation for Jolie2wsdl

private static class JolieDummyArgumentHandler implements CommandLineParser.ArgumentHandler {

    private String portName;
    private String tns;
    private String address;
    private String outputFile;

    public int onUnrecognizedArgument(List< String> argumentsList, int index)
            throws CommandLineException {
        if ("--tns".equals(argumentsList.get(index))) {
            index++;
            tns = argumentsList.get(index);
        } else if ("--pN".equals(argumentsList.get(index))) {
            index++;
            portName = argumentsList.get(index);
        } else if ("--addr".equals(argumentsList.get(index))) {
            index++;
            address = argumentsList.get(index);
        } else if ("--oF".equals(argumentsList.get(index))) {
            index++;
            outputFile = argumentsList.get(index);
        } else {
            throw new CommandLineException("Unrecognized command line option: " + argumentsList.get(index));
        }

        return index;
    }
}

If you want i can modify the documentation or work on the parser itself

Tnks

Balint

Bug in http multipart

It seems to me that there is an error in multiPartFormData message reception.
In this line of method parsePart of class MultiPartFormDataParser we divide part header from content

String[] hc = part.split( HttpUtils.CRLF + HttpUtils.CRLF );

But, if the content of the part contains a couple of HttpUtils.CRLF + HttpUtils.CRLF, the parser will cut the content.

A possible fix should be:

String[] hc = part.split( HttpUtils.CRLF + HttpUtils.CRLF, 2 );

Am I wrong?

Deep Copy and Aliases in Inline Trees

Right now, the syntax for Inline Trees (ITs) supports only assignments, for example:

{ .x = 4, .y = 6 }

We should also support deep copies (allowing for nested ITs) and aliases (->), for example:

{ .x << { .z = 3, .i = 2 }, .y -> a }

MongoDB

@jolie/developers

Hi guys

I was wandering if any of you would be interested into the implementation of Jolie Service Library for MongoDB. Would be nice to have someone to exchange idea on how to do this stuff
Regards
Balint

SOAP message charset bug

take the following service and transform it in a web service using jolie2wsdl.

If you send a SOAP message with a request message that contains more than two special characters like "ร ", the service will reply with a truncated message.

Service

include "console.iol"

execution{ concurrent }

type TestType: void {
    .message: string
}

type TestTypeR: void {
    .message: string
}

interface MyInterface {
    RequestResponse:
        test( TestType )( TestTypeR )
}

inputPort MyPort {
    Location: "socket://localhost:9000"
    Protocol: soap {
        .wsdl = "test.wsdl";
        .wsdl.port = "MyPortServicePort"
    }
    Interfaces: MyInterface
}

main {  
    test( request )( response ) {
        response.message = request.message
    }
}

Request message example that raises the bug:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:prov="prova.xsd">
   <soapenv:Header/>
   <soapenv:Body>
      <prov:test>
         <message>etssร ร ร </message>
      </prov:test>
   </soapenv:Body>
</soapenv:Envelope>

Generated WSDL:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="prova.wsdl" xmlns:tns="prova.wsdl" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd1="prova.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <wsdl:types>
    <xs:schema targetNamespace="prova.xsd" xmlns:sch="prova.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema"><xs:element name="test"><xs:complexType><xs:sequence><xs:element maxOccurs="1" minOccurs="1" name="message" type="xs:string"/></xs:sequence></xs:complexType></xs:element><xs:element name="testResponse"><xs:complexType><xs:sequence><xs:element maxOccurs="1" minOccurs="1" name="message" type="xs:string"/></xs:sequence></xs:complexType></xs:element></xs:schema>
  </wsdl:types>
  <wsdl:message name="TestTypeR">
    <wsdl:part name="body" element="xsd1:testResponse"/>
  </wsdl:message>
  <wsdl:message name="TestType">
    <wsdl:part name="body" element="xsd1:test"/>
  </wsdl:message>
  <wsdl:portType name="MyPort">
    <wsdl:operation name="test">
      <wsdl:input message="tns:TestType"/>
      <wsdl:output message="tns:TestTypeR"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="MyPortSOAPBinding" type="tns:MyPort">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http/"/>
    <wsdl:operation name="test">
      <soap:operation soapAction="test" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="MyPortService">
    <wsdl:port name="MyPortServicePort" binding="tns:MyPortSOAPBinding">
      <soap:address location="http://localhost:9000"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

MongoDB

@jolie/developers

Hi guys

I was wandering if any of you would be interested into the implementation of Jolie Service Library for MongoDB. Would be nice to have someone to exchange idea on how to do this stuff
Regards
Balint

HTTP - implement content negotiation

According to HTTP RFC 7231 we should accept content negotiation over the Accept and the Accept-Charset headers ("Accept-Encoding" is already supported by us, "Accept-Language" needs to be handled at user's side).
These seem very useful features to me. At the moment I would prefer to just implement the simple (unweighted syntax).

https://tools.ietf.org/html/rfc7231#section-5.3

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.