Skip to content

Commit

Permalink
Adds more docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
simonbrowndotje committed Dec 28, 2023
1 parent 248a01a commit 8cc1095
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 0 deletions.
13 changes: 13 additions & 0 deletions contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
layout: default
title: Contributing
nav_order: 19
permalink: /contributing
---

# Contributing

## Can I submit a pull request?

It depends on the nature of the change - please open an issue first to discuss it.
Unsolicited pull requests will likely be ignored/closed.
43 changes: 43 additions & 0 deletions java/faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
layout: default
title: FAQ
parent: Structurizr for Java
nav_order: 9
permalink: /java/faq
---

# Frequently asked questions

## How do I build from source?

To build from the sources (you'll need git and Java 17+ installed):

```
git clone https://github.com/structurizr/java.git structurizr-java
cd structurizr-java
./gradlew
```

This will create two `.jar` files:

- structurizr-client/build/libs/structurizr-client-{version}.jar
- structurizr-core/build/libs/structurizr-core-{version}.jar

## Why are many classes final with package-protected members, and not open to extension?

First and foremost, this repo is a client library for the Structurizr cloud service and on-premises installation.
It allows you to write Java code to create an in-memory object graph representing a software architecture model and
views (a "workspace"), serialize that to JSON, and upload it via a web API.
The workspace has an [OpenAPI definition](https://github.com/structurizr/json/), but this library also implements a
number of rules (think of them as the "business logic") to ensure that the workspace is valid.
These rules include, for example, ensuring that all containers with a software system have unique names,
and that you can't add components to a system context view.

Removing the `final` modifier from the classes and leaving them open for extension allows you to bypass/break these rules,
which will likely lead to the serialized workspace definitions being incompatible with the various diagram rendering tools
(i.e. the Structurizr cloud service/on-premises installation/Lite, plus the PlantUML/Mermaid exporters).
The output of this library also needs to be compatible with client libraries written in other languages.

You are welcome to fork this library for your own purposes.
Alternatively, you can build a thin wrapper around the library, to provide your own custom functionality,
or perhaps a more fluent API.
105 changes: 105 additions & 0 deletions java/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
layout: default
title: Getting started
parent: Structurizr for Java
nav_order: 1
permalink: /java/getting-started
---

# Getting started

Here is a quick overview of how to get started with Structurizr for Java so that you can create a workspace using Java code.
You can find a full code example at [GettingStarted.java](https://github.com/structurizr/examples/blob/main/java/src/main/java/com/structurizr/example/GettingStarted.java)
and the published workspace at [https://structurizr.com/share/25441](https://structurizr.com/share/25441).
See [structurizr-examples](https://github.com/structurizr/examples/tree/main/java/src/main/java/com/structurizr/example) for more examples.

## 1. Dependencies

The Structurizr for Java binaries are hosted on [Maven Central](https://repo1.maven.org/maven2/com/structurizr/structurizr-client/)
and the dependency coordinates for `structurizr-client` (which has a transient dependency on `structurizr-core`) is as follows.

- `com.structurizr:structurizr-client`

## 2. Create a Java program

We'll start by creating a new Java class with a ```main``` method as follows:

```java
public class GettingStarted {

public static void main(String[] args) throws Exception {
// your Structurizr code will go here
}

}
```

## 3. Create a model

The first step is to create a workspace in which the software architecture model will reside.

```java
Workspace workspace = new Workspace("Getting Started", "This is a model of my software system.");
Model model = workspace.getModel();
```

Now let's add some elements to the model to describe a user using a software system.

```java
Person user = model.addPerson("User", "A user of my software system.");
SoftwareSystem softwareSystem = model.addSoftwareSystem("Software System", "My software system.");
user.uses(softwareSystem, "Uses");
```

## 4. Create a view

With the model created, we need to create some views with which to visualise it.

```java
ViewSet views = workspace.getViews();
SystemContextView contextView = views.createSystemContextView(softwareSystem, "SystemContext", "An example of a System Context diagram.");
contextView.addAllSoftwareSystems();
contextView.addAllPeople();
```

## 5. Add some colour and shapes

Optionally, elements and relationships can be styled by specifying colours, sizes and shapes.

```java
Styles styles = views.getConfiguration().getStyles();
styles.addElementStyle(Tags.SOFTWARE_SYSTEM).background("#1168bd").color("#ffffff");
styles.addElementStyle(Tags.PERSON).background("#08427b").color("#ffffff").shape(Shape.Person);
```

## 6. Next steps

The code to this point will create a workspace, and now you have options as to what do to next.

### 6a. Upload to the Structurizr cloud service

The Structurizr cloud service provides a web API to get and put workspaces,
and an API client is provided via the [WorkspaceApiClient](https://github.com/structurizr/java/blob/master/structurizr-client/src/com/structurizr/api/WorkspaceApiClient.java) class.
Assuming that you have a cloud service account, have created a workspace, and have the workspace ID plus API key/secret pair:

```java
WorkspaceApiClient client = new WorkspaceApiClient("key", "secret");
client.putWorkspace(id, workspace);
```

### 6b: Upload to a Structurizr on-premises installation

This is the same as above, with the exception that you'll need to additionally provide an API endpoint:

```java
WorkspaceApiClient client = new WorkspaceApiClient("http://localhost:8080/api", "key", "secret");
client.putWorkspace(id, workspace);
```

### 6c. Export to a JSON file

To export the workspace to a JSON file:

```java
WorkspaceUtils.saveWorkspaceToJson(workspace, new File("workspace.json"));
```
Binary file added java/images/implied-relationships.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
102 changes: 102 additions & 0 deletions java/implied-relationships.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
layout: default
title: Implied relationships
parent: Structurizr for Java
nav_order: 3
permalink: /java/implied-relationships
---

# Implied relationships

By default, the Structurizr for Java library will not create implied relationships.
For example, imagine that you have two components in different containers:

```
SoftwareSystem softwareSystem = model.addSoftwareSystem("Software System");
Container container1 = softwareSystem.addContainer("Container 1");
Component component1 = container1.addComponent("Component 1");
Container container2 = softwareSystem.addContainer("Container 2");
Component component2 = container2.addComponent("Component 2");
```

And you create a relationship between them:

```
component1.uses(component2, "Sends data X to");
```

At this point, the model contains a single relationship between the two components,
but there are three other implied relationships that could be added:

![Implied relationships](images/implied-relationships.png)

| Type | Description |
|----------|-----------------------------------------|
| Explicit | Component 1 sends data X to Component 2 |
| Implied | Container 1 Sends data X to Component 2 |
| Implied | Component 1 Sends data X to Container 2 |
| Implied | Container 1 Sends data X to Container 2 |

To have the client library create these for you, set an `ImpliedRelationshipsStrategy` implementation on your model.
Provided implementations are as follows.

## DefaultImpliedRelationshipsStrategy

This strategy does not create any implied relationships.

```
model.setImpliedRelationshipsStrategy(new DefaultImpliedRelationshipsStrategy()); // default
component1.uses(component2, "Sends data X to");
```

Relationships that exist in the model:

| Type | Description |
|----------|-----------------------------------------|
| Explicit | Component 1 sends data X to Component 2 |

## CreateImpliedRelationshipsUnlessSameRelationshipExistsStrategy

This strategy creates implied relationships between all valid combinations of the parent elements, unless the same
relationship already exists between them.

```
model.setImpliedRelationshipsStrategy(new CreateImpliedRelationshipsUnlessAnyRelationshipExistsStrategy());
component1.uses(component2, "Sends data X to");
```

Relationships that exist in the model:

| Type | Description |
|----------|-----------------------------------------|
| Explicit | Component 1 sends data X to Component 2 |
| Implied | Container 1 Sends data X to Component 2 |
| Implied | Component 1 Sends data X to Container 2 |
| Implied | Container 1 Sends data X to Container 2 |

Although appealing, this strategy typically results in an explosion of relationships in the model,
and therefore isn't particularly useful in real-world usage.

## CreateImpliedRelationshipsUnlessAnyRelationshipExistsStrategy

This strategy creates implied relationships between all valid combinations of the parent elements, unless *any*
relationship already exists between them.

```
model.setImpliedRelationshipsStrategy(new CreateImpliedRelationshipsUnlessAnyRelationshipExistsStrategy());
container1.uses(container2, "Sends data to");
component1.uses(component2, "Sends data X to");
```

Relationships that exist in the model:

| Type | Description |
|----------|-----------------------------------------|
| Explicit | Container 1 Sends data to Container 2 |
| Explicit | Component 1 sends data X to Component 2 |
| Implied | Component 1 Sends data X to Container 2 |
| Implied | Container 1 Sends data X to Component 2 |

This strategy is useful when you want to show a summary relationship at higher levels in the model,
especially when multiple implied relationships could be created between elements.
88 changes: 88 additions & 0 deletions java/workspace-api-client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
layout: default
title: Workspace API client
parent: Structurizr for Java
nav_order: 2
permalink: /java/workspace-api
---

# Workspace API client

The Structurizr cloud service and on-premises installation provide a web API to get and put workspaces,
and an API client is provided via the [WorkspaceApiClient](https://github.com/structurizr/java/blob/master/structurizr-client/src/com/structurizr/api/WorkspaceApiClient.java) class.

Each workspace has its own API key and secret, the values for which can be found on the workspace settings page.
You will need these values (plus the workspace ID) when creating a `WorkspaceApiClient` instance:

For the cloud service:

```java
WorkspaceApiClient client = new WorkspaceApiClient("key", "secret");
```

If you're using the on-premises installation, you'll need the three argument version of the constructor where you can also specify the API URL.

```java
WorkspaceApiClient client = new WorkspaceApiClient("url", "key", "secret");
```

## Usage

The following operations are available on the API client.

### Get workspace

This allows you to get the content of a remote workspace.

```java
Workspace workspace = client.getWorkspace(123456);
```

By default, a copy of the workspace (as a JSON document) is archived to the current working directory. You can modify this behaviour by calling ```setWorkspaceArchiveLocation```. A ```null``` value will disable archiving.

### Put workspace

This allows you to overwrite an existing remote workspace.
If the ```mergeFromRemote``` property (on the `WorkspaceApiClient` instance) is set to `true` (this is the default),
any layout information (i.e. the location of boxes on diagrams) is preserved where possible (i.e. where diagram elements haven't been renamed).

```java
client.putWorkspace(123456, workspace);
```

### Locking/unlocking a workspace

Paid cloud service workspaces and the on-premises installation have a workspace locking feature to prevent concurrent updates.

```java
client.lockWorkspace(1234);
```

This method returns a boolean; ```true``` if the workspace could be locked, ```false``` otherwise.

Similarly, you can unlock a workspace.

```java
client.unlockWorkspace(1234);
```

This method also returns a boolean; ```true``` if the workspace could be unlocked, ```false``` otherwise.

## Troubleshooting

### SSL handshake errors

SSL handshake errors are likely if using a self-signed certificate with the on-premises installation,
because the Structurizr client runtime won't trust a self-signed certificate by default.

If this happens, you can use the ```javax.net.ssl.trustStore``` JVM option to point to your keystore. For example:

```
java -Djavax.net.ssl.trustStore=/some/path/to/keystore.jks YourJavaProgram
```

Alternatively, you can specify this property in your Java program:

```
System.setProperty("javax.net.ssl.trustStore", "/some/path/to/keystore.jks");
```

0 comments on commit 8cc1095

Please sign in to comment.