├── .gitignore ├── README.md ├── pom.xml ├── short-license.txt └── src ├── main └── java │ └── com │ └── bmdsoftware │ └── pacs │ └── dicoogle │ └── ipfs │ ├── IPFSJettyPlugin.java │ ├── IPFSPluginSet.java │ ├── IPFSStore.java │ └── services │ ├── IPFSListWebService.java │ └── IPFSStatusWebService.java └── test ├── java └── com │ └── bmdsoftware │ └── pacs │ └── dicoogle │ └── ipfs │ ├── TestIPFS.java │ └── TestStorage.java └── resources └── DoseSR_GE_01.DCM /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | 3 | # Eclipse 4 | .classpath 5 | .project 6 | .settings/ 7 | 8 | # Intellij 9 | .idea/ 10 | *.iml 11 | *.iws 12 | 13 | # Mac 14 | .DS_Store 15 | 16 | # Maven 17 | log/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Dicoogle IPFS Storage Plugin 2 | ======================== 3 | 4 | This is a [Dicoogle](https://www.dicoogle.com) plugin to support the storage of files over [IPFS](https://ipfs.io/). 5 | 6 | Getting Started 7 | --------------- 8 | 9 | [IPFS](https://ipfs.io/) is a P2P distributed file system that targets to connect all computing devices with 10 | the same system of files. IPFS provides a high-throughput, content-addressed block storage model, with 11 | addressed with a hash URI. Dicoogle IPFS is as far as we know, the first PACS archive supporting [DICOM](https://www.dicomstandard.org/) communications 12 | with IPFS capabilities. 13 | 14 | 15 | ### Run IPFS Daemon 16 | 17 | 18 | 1. First, go to and download the IPFS. You can use Go IPFS Daemon. 19 | 2. Run init to create the hash files and keys with: 20 | 21 | $ ./ipfs init 22 | 23 | 3. Start the daemon: 24 | 25 | $ ./ipfs daemon 26 | 27 | It should retrieve something similar: 28 | 29 | ``` 30 | Initializing daemon... 31 | Swarm listening on /ip4/127.0.0.1/tcp/4001 32 | Swarm listening on /ip4/169.254.195.127/tcp/4001 33 | Swarm listening on /ip4/172.20.20.25/tcp/4001 34 | Swarm listening on /ip4/192.168.1.72/tcp/4001 35 | Swarm listening on /ip6/::1/tcp/4001 36 | Swarm listening on /p2p-circuit/ipfs/QmPYwyhd9WfH6cmyXh4SJpSkxweeHmUbohao6g4H4zhD3G 37 | Swarm announcing /ip4/127.0.0.1/tcp/4001 38 | Swarm announcing /ip4/169.254.195.127/tcp/4001 39 | Swarm announcing /ip4/172.20.20.25/tcp/4001 40 | Swarm announcing /ip4/192.168.1.72/tcp/4001 41 | Swarm announcing /ip4/2.83.194.251/tcp/60663 42 | Swarm announcing /ip6/::1/tcp/4001 43 | API server listening on /ip4/127.0.0.1/tcp/5001 44 | Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080 45 | Daemon is ready 46 | ``` 47 | 48 | 49 | ### Using your plugin 50 | 51 | 1. Copy your plugin's package with dependencies (target/ipfs-plugin-1.0.0-SNAPSHOT-jar-with-dependencies.jar) 52 | to the "Plugins" folder inside the root folder of Dicoogle. 53 | 54 | 2. Run Dicoogle. The plugin will be automatically included. 55 | 56 | 57 | ### Configuration 58 | 59 | You can configure the IPFS endpoint in the Plugin settings. Check here: 60 | 61 | 62 | ``` 63 | | => cat Plugins/settings/IPFS.xml 64 | 65 | 66 | 67 | /ip4/127.0.0.1/tcp/5001 68 | 69 | 70 | ``` 71 | 72 | ### Available services 73 | If Dicoogle is running on PORT 8082: 74 | 75 | #### Check the current status 76 | Status Web service available at: ipfs/status?action=status 77 | 78 | URL: http://localhost:8082/ipfs/status?action=status 79 | 80 | #### Check the number of local files on IPFS 81 | List Web service available at: ipfs/status?action=fileCount 82 | 83 | URL: http://localhost:8082/ipfs/list?action=fileCount 84 | 85 | #### List of local files hashes on IPFS 86 | List Web service available at: ipfs/status?action=fileList 87 | 88 | URL: http://localhost:8082/ipfs/list?action=fileList 89 | 90 | 91 | ### Test data 92 | 93 | This repository uses DICOM data for testing. The DICOM files listed under `src/test/resources` are made available by [NEMA](medical.nema.org) in ftp://medical.nema.org/medical/dicom/DataSets/WG02/RDSR/. 94 | 95 | ### Troubleshooting 96 | 97 | By default Dicoogle and IPFS Daemon open the 8080 tcp port, so one of application should change the port to avoid 98 | problems. 99 | 100 | 101 | ## Use case 102 | 103 | 1) Store medical imaging over IPFS 104 | 2) Failures 105 | 3) Avoid changes in medical imaging 106 | 4) Allow tracebility 107 | 108 | 109 | 110 | 111 | ## Support and consulting 112 | 113 | [BMD Software](https://www.bmd-software.com) 114 | 115 | Please contact [BMD Software](https://www.bmd-software.com) for professional support and consulting services. 116 | 117 | 118 | 119 | Platforms 120 | ---------- 121 | 122 | Dicoogle IPFS has been tested in: 123 | 124 | - Windows 125 | - Linux 126 | - Mac OS X 127 | - FreeBSD and OpenBSD 128 | 129 | For more information, please visit http://www.dicoogle.com 130 | 131 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.bmdsofware.dicoogle 6 | ipfs-plugin 7 | ipfs 8 | 1.0.0-SNAPSHOT 9 | jar 10 | 11 | 12 | UTF-8 13 | 14 | 15 | 3.0.0 16 | 17 | 18 | 9.0.3.v20130506 19 | 20 | 21 | v1.3.3 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.apache.maven.plugins 29 | maven-compiler-plugin 30 | 2.3.2 31 | 32 | 35 | 1.8 36 | 1.8 37 | 38 | 39 | 40 | maven-assembly-plugin 41 | 42 | 43 | jar-with-dependencies 44 | 45 | 46 | 47 | 48 | 49 | 50 | make-assembly 51 | package 52 | 53 | single 54 | 55 | 56 | 57 | 58 | 59 | com.mycila 60 | license-maven-plugin 61 | 2.4 62 | 63 |
./short-license.txt
64 | 65 | **/*.java 66 | 67 | 68 | **/package-info.java 69 | 70 |
71 | 72 | 73 | 74 | check 75 | 76 | 77 | 78 |
79 |
80 |
81 | 82 | 83 | 84 | maven-restlet 85 | Public online Restlet repository 86 | https://maven.restlet.org 87 | 88 | 89 | 90 | mavencentral 91 | https://repo1.maven.org/maven2/ 92 | 93 | true 94 | 95 | 96 | 97 | 98 | dcm4che 99 | https://www.dcm4che.org/maven2/ 100 | 101 | true 102 | 103 | 104 | 105 | 106 | jitpack.io 107 | https://jitpack.io 108 | 109 | 110 | 111 | mi 112 | https://bioinformatics.ua.pt/maven/content/repositories/mi 113 | 114 | false 115 | 116 | 117 | 118 | 119 | mi-snapshots 120 | https://bioinformatics.ua.pt/maven/content/repositories/mi-snapshots 121 | 122 | true 123 | 124 | 125 | 126 | 127 | 128 | 129 | org.restlet.jse 130 | org.restlet.ext.json 131 | 2.1.2 132 | 133 | 134 | 135 | pt.ua.ieeta 136 | dicoogle-sdk 137 | ${dicoogle.version} 138 | 139 | 140 | 141 | org.eclipse.jetty 142 | jetty-webapp 143 | ${jetty.version} 144 | 145 | 146 | 147 | com.github.ipfs 148 | java-ipfs-http-client 149 | ${ipfs-client.version} 150 | 151 | 152 | 153 | junit 154 | junit 155 | 4.13.1 156 | test 157 | 158 | 159 |
160 | -------------------------------------------------------------------------------- /short-license.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 BMD software, Lda 2 | 3 | This file is part of Dicoogle/${project.name}. 4 | 5 | Dicoogle/${project.name} is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | Dicoogle/${project.name} is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with Dicoogle. If not, see . 17 | -------------------------------------------------------------------------------- /src/main/java/com/bmdsoftware/pacs/dicoogle/ipfs/IPFSJettyPlugin.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 BMD software, Lda 3 | * 4 | * This file is part of Dicoogle/ipfs. 5 | * 6 | * Dicoogle/ipfs is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Dicoogle/ipfs is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Dicoogle. If not, see . 18 | */ 19 | package com.bmdsoftware.pacs.dicoogle.ipfs; 20 | 21 | import com.bmdsoftware.pacs.dicoogle.ipfs.services.IPFSListWebService; 22 | import com.bmdsoftware.pacs.dicoogle.ipfs.services.IPFSStatusWebService; 23 | import io.ipfs.api.IPFS; 24 | import org.eclipse.jetty.server.handler.HandlerList; 25 | import org.eclipse.jetty.servlet.ServletContextHandler; 26 | import org.eclipse.jetty.servlet.ServletHolder; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | import pt.ua.dicoogle.sdk.JettyPluginInterface; 30 | import pt.ua.dicoogle.sdk.core.DicooglePlatformInterface; 31 | import pt.ua.dicoogle.sdk.core.PlatformCommunicatorInterface; 32 | import pt.ua.dicoogle.sdk.settings.ConfigurationHolder; 33 | 34 | /** 35 | * IPFS Jetty Servlet plugin. 36 | * 37 | * @author Luís A. Bastião Silva - 38 | * @author Eriksson Monteiro - 39 | */ 40 | public class IPFSJettyPlugin implements JettyPluginInterface, PlatformCommunicatorInterface { 41 | private static final Logger logger = LoggerFactory.getLogger(IPFSJettyPlugin.class); 42 | 43 | private boolean enabled; 44 | private ConfigurationHolder settings; 45 | private DicooglePlatformInterface platform; 46 | private final IPFSStatusWebService statusWebService; 47 | private final IPFSListWebService listWebService; 48 | private IPFS ipfs; 49 | 50 | public IPFSJettyPlugin(IPFS ipfs) { 51 | this.ipfs = ipfs; 52 | this.statusWebService = new IPFSStatusWebService(ipfs); 53 | this.listWebService = new IPFSListWebService(ipfs); 54 | this.enabled = true; 55 | } 56 | 57 | @Override 58 | public void setPlatformProxy(DicooglePlatformInterface pi) { 59 | this.platform = pi; 60 | // since web service is not a plugin interface, the platform interface must be provided manually 61 | this.statusWebService.setPlatformProxy(pi); 62 | } 63 | 64 | @Override 65 | public String getName() { 66 | return "IPFS"; 67 | } 68 | 69 | @Override 70 | public boolean enable() { 71 | this.enabled = true; 72 | return true; 73 | } 74 | 75 | @Override 76 | public boolean disable() { 77 | this.enabled = false; 78 | return true; 79 | } 80 | 81 | @Override 82 | public boolean isEnabled() { 83 | return this.enabled; 84 | } 85 | 86 | @Override 87 | public void setSettings(ConfigurationHolder settings) { 88 | this.settings = settings; 89 | // use settings here 90 | } 91 | 92 | @Override 93 | public ConfigurationHolder getSettings() { 94 | return settings; 95 | } 96 | 97 | 98 | @Override 99 | public HandlerList getJettyHandlers() { 100 | 101 | ServletContextHandler handler = new ServletContextHandler(); 102 | handler.setContextPath("/ipfs"); 103 | handler.addServlet(new ServletHolder(this.statusWebService), "/status"); 104 | handler.addServlet(new ServletHolder(this.listWebService), "/list"); 105 | handler.addServlet(new ServletHolder(this.statusWebService), "/chain"); 106 | handler.addServlet(new ServletHolder(this.statusWebService), "/hash"); 107 | HandlerList l = new HandlerList(); 108 | l.addHandler(handler); 109 | 110 | 111 | return l; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/bmdsoftware/pacs/dicoogle/ipfs/IPFSPluginSet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 BMD software, Lda 3 | * 4 | * This file is part of Dicoogle/ipfs. 5 | * 6 | * Dicoogle/ipfs is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Dicoogle/ipfs is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Dicoogle. If not, see . 18 | */ 19 | package com.bmdsoftware.pacs.dicoogle.ipfs; 20 | 21 | import io.ipfs.api.IPFS; 22 | import net.xeoh.plugins.base.annotations.PluginImplementation; 23 | import org.apache.commons.configuration.XMLConfiguration; 24 | import org.restlet.resource.ServerResource; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | import pt.ua.dicoogle.sdk.*; 28 | import pt.ua.dicoogle.sdk.settings.ConfigurationHolder; 29 | 30 | import java.io.IOException; 31 | import java.util.Collection; 32 | import java.util.Collections; 33 | 34 | /** 35 | * The main plugin set. 36 | * 37 | * This is the entry point for all plugins. 38 | * 39 | * @author Luís A. Bastião Silva - 40 | * @author Eriksson Monteiro - 41 | */ 42 | @PluginImplementation 43 | public class IPFSPluginSet implements PluginSet { 44 | // use slf4j for logging purposes 45 | private static final Logger logger = LoggerFactory.getLogger(IPFSPluginSet.class); 46 | 47 | // We will list each of our plugins as an attribute to the plugin set 48 | 49 | private final IPFSJettyPlugin jettyWeb; 50 | private final IPFSStore storage; 51 | private String endpoint = "/ip4/127.0.0.1/tcp/5001"; 52 | private IPFS ipfs; 53 | private ConfigurationHolder settings; 54 | 55 | public IPFSPluginSet() throws IOException { 56 | logger.info("Initializing IPFS Plugin Set"); 57 | 58 | // construct all plugins here 59 | logger.info("IPFS connecting to .. " + endpoint); 60 | try{ 61 | IPFS ipfs = new IPFS(endpoint); 62 | } 63 | catch(Exception e){ 64 | logger.error("IPFS is not ready to connect. Please, configure IPFS daemon.", e); 65 | } 66 | // Initialize other plugins and services 67 | this.jettyWeb = new IPFSJettyPlugin(ipfs); 68 | this.storage = new IPFSStore(ipfs); 69 | logger.info("IPFS Plugin Set was initialized."); 70 | } 71 | 72 | 73 | @Override 74 | public Collection getIndexPlugins() { 75 | 76 | return Collections.EMPTY_LIST; 77 | } 78 | 79 | @Override 80 | public Collection getQueryPlugins() { 81 | return Collections.EMPTY_LIST; 82 | } 83 | 84 | /** 85 | * This method is used to retrieve a name for identifying the plugin set. Keep it as a constant value. 86 | * 87 | * @return a unique name for the plugin set 88 | */ 89 | @Override 90 | public String getName() { 91 | return "IPFS"; 92 | } 93 | 94 | @Override 95 | public Collection getRestPlugins() { 96 | return Collections.EMPTY_LIST; 97 | } 98 | 99 | @Override 100 | public Collection getJettyPlugins() { 101 | return Collections.singleton(this.jettyWeb); 102 | } 103 | 104 | @Override 105 | public void shutdown() { 106 | } 107 | 108 | @Override 109 | public Collection getStoragePlugins() { 110 | return Collections.singleton(this.storage); 111 | } 112 | 113 | @Override 114 | public ConfigurationHolder getSettings() { 115 | return this.settings; 116 | } 117 | 118 | @Override 119 | public void setSettings(ConfigurationHolder xmlSettings) { 120 | this.settings = xmlSettings; 121 | XMLConfiguration cnf = this.settings.getConfiguration(); 122 | cnf.setThrowExceptionOnMissing(true); 123 | 124 | try { 125 | endpoint = cnf.getString("ipfs.endpoint", "/ip4/127.0.0.1/tcp/5001"); 126 | 127 | if (!cnf.containsKey("ipfs.endpoint")) { 128 | cnf.setProperty("ipfs.endpoint", "/ip4/127.0.0.1/tcp/5001"); 129 | } 130 | } catch (Exception ex) { 131 | logger.warn("Failed to configure plugin: required fields are missing!", ex); 132 | } 133 | } 134 | 135 | 136 | } -------------------------------------------------------------------------------- /src/main/java/com/bmdsoftware/pacs/dicoogle/ipfs/IPFSStore.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 BMD software, Lda 3 | * 4 | * This file is part of Dicoogle/ipfs. 5 | * 6 | * Dicoogle/ipfs is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Dicoogle/ipfs is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Dicoogle. If not, see . 18 | */ 19 | package com.bmdsoftware.pacs.dicoogle.ipfs; 20 | 21 | import io.ipfs.api.IPFS; 22 | import io.ipfs.api.MerkleNode; 23 | import io.ipfs.api.NamedStreamable; 24 | import io.ipfs.multihash.Multihash; 25 | import org.dcm4che2.data.DicomObject; 26 | import org.dcm4che2.io.DicomInputStream; 27 | import org.dcm4che2.io.DicomOutputStream; 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | import pt.ua.dicoogle.sdk.StorageInputStream; 31 | import pt.ua.dicoogle.sdk.StorageInterface; 32 | import pt.ua.dicoogle.sdk.settings.ConfigurationHolder; 33 | 34 | import java.io.ByteArrayInputStream; 35 | import java.io.ByteArrayOutputStream; 36 | import java.io.IOException; 37 | import java.io.InputStream; 38 | import java.net.URI; 39 | import java.net.URISyntaxException; 40 | import java.util.ArrayList; 41 | import java.util.Collection; 42 | import java.util.Iterator; 43 | import java.util.UUID; 44 | 45 | /** 46 | * @author Luís A. Bastião Silva - 47 | */ 48 | public class IPFSStore implements StorageInterface { 49 | 50 | private static final Logger logger = LoggerFactory.getLogger(IPFSStore.class); 51 | 52 | private boolean enabled = true; 53 | 54 | private IPFS ipfs = null; 55 | 56 | 57 | public IPFSStore(IPFS ipfs) { 58 | this.ipfs = ipfs; 59 | } 60 | 61 | @Override 62 | public String getScheme() { 63 | return "ipfs"; 64 | } 65 | 66 | @Override 67 | public Iterable at(final URI location, Object... objects) { 68 | Iterable c = new Iterable() { 69 | 70 | @Override 71 | public Iterator iterator() { 72 | Collection c2 = new ArrayList<>(); 73 | StorageInputStream s = new StorageInputStream() { 74 | 75 | @Override 76 | public URI getURI() { 77 | return location; 78 | } 79 | 80 | @Override 81 | public InputStream getInputStream() throws IOException { 82 | Multihash filePointer = Multihash.fromBase58(location.toString().replaceFirst("ipfs://", "")); 83 | 84 | byte[] fileContents = new byte[0]; 85 | try { 86 | fileContents = ipfs.cat(filePointer); 87 | } catch (IOException e) { 88 | logger.error("Failed to retrieve object", e); 89 | return null; 90 | } 91 | 92 | ByteArrayInputStream bin = new ByteArrayInputStream(fileContents); 93 | return bin; 94 | } 95 | 96 | @Override 97 | public long getSize() throws IOException { 98 | Multihash filePointer = Multihash.fromBase58(location.toString().replaceFirst("ipfs://", "")); 99 | return ipfs.get(filePointer).length; 100 | } 101 | }; 102 | c2.add(s); 103 | return c2.iterator(); 104 | } 105 | }; 106 | return c; 107 | 108 | } 109 | 110 | @Override 111 | public URI store(DicomObject dicomObject, Object... objects) { 112 | 113 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 114 | DicomOutputStream dos = new DicomOutputStream(bos); 115 | try { 116 | dos.writeDicomFile(dicomObject); 117 | } catch (IOException ex) { 118 | logger.error("Failed to store object", ex); 119 | } 120 | 121 | 122 | NamedStreamable.ByteArrayWrapper file = new NamedStreamable.ByteArrayWrapper(UUID.randomUUID().toString(), bos.toByteArray()); 123 | MerkleNode addResult = null; 124 | try { 125 | addResult = ipfs.add(file).get(0); 126 | } catch (IOException e) { 127 | logger.error("Failed to store object", e); 128 | return null; 129 | } 130 | 131 | // Retrieve the hash 132 | try { 133 | return new URI("ipfs://" + addResult.hash.toBase58()); 134 | } catch (URISyntaxException e) { 135 | logger.error("Failed to build uri ", e); 136 | return null; 137 | } 138 | } 139 | 140 | @Override 141 | public URI store(DicomInputStream dicomInputStream, Object... objects) throws IOException { 142 | 143 | DicomObject obj = dicomInputStream.readDicomObject(); 144 | return store(obj); 145 | } 146 | 147 | @Override 148 | public void remove(URI uri) { 149 | try { 150 | ipfs.pin.rm(Multihash.fromBase58(uri.toString().replaceFirst("ipfs://", ""))); 151 | } catch (IOException e) { 152 | logger.error("Failed to remove pin", e); 153 | } 154 | } 155 | 156 | @Override 157 | public String getName() { 158 | return "ipfs-storage"; 159 | } 160 | 161 | @Override 162 | public boolean enable() { 163 | this.enabled = true; 164 | return true; 165 | } 166 | 167 | @Override 168 | public boolean disable() { 169 | this.enabled = false; 170 | return true; 171 | } 172 | 173 | @Override 174 | public boolean isEnabled() { 175 | return this.enabled; 176 | } 177 | 178 | @Override 179 | public ConfigurationHolder getSettings() { 180 | return null; 181 | } 182 | 183 | @Override 184 | public void setSettings(ConfigurationHolder configurationHolder) { 185 | 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/com/bmdsoftware/pacs/dicoogle/ipfs/services/IPFSListWebService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 BMD software, Lda 3 | * 4 | * This file is part of Dicoogle/ipfs. 5 | * 6 | * Dicoogle/ipfs is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Dicoogle/ipfs is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Dicoogle. If not, see . 18 | */ 19 | package com.bmdsoftware.pacs.dicoogle.ipfs.services; 20 | 21 | import io.ipfs.api.IPFS; 22 | import org.eclipse.jetty.http.HttpStatus; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | import pt.ua.dicoogle.sdk.core.DicooglePlatformInterface; 26 | import pt.ua.dicoogle.sdk.core.PlatformCommunicatorInterface; 27 | 28 | import javax.servlet.http.HttpServlet; 29 | import javax.servlet.http.HttpServletRequest; 30 | import javax.servlet.http.HttpServletResponse; 31 | import java.io.IOException; 32 | import java.io.PrintWriter; 33 | import java.util.stream.Collectors; 34 | 35 | /** 36 | * IPFS Jetty Plugin - Status 37 | * 38 | * @author Luís A. Bastião Silva - 39 | * @author Eriksson Monteiro - 40 | * @author Rui Lebre - 41 | */ 42 | public class IPFSListWebService extends HttpServlet implements PlatformCommunicatorInterface { 43 | private static final Logger logger = LoggerFactory.getLogger(IPFSListWebService.class); 44 | 45 | private DicooglePlatformInterface platform; 46 | private IPFS ipfs = null; 47 | 48 | public IPFSListWebService(IPFS ipfs) { 49 | this.ipfs = ipfs; 50 | } 51 | 52 | @Override 53 | protected void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException { 54 | 55 | String action = req.getParameter("action"); 56 | if (action == null) { 57 | response.sendError(HttpStatus.BAD_REQUEST_400, "No action provided"); 58 | return; 59 | } 60 | 61 | response.setContentType("text/json;charset=utf-8"); 62 | PrintWriter out = response.getWriter(); 63 | 64 | if (action.equalsIgnoreCase("fileCount")) { 65 | response.setStatus(HttpStatus.OK_200); 66 | 67 | out.print("{\"action\":\"fileCount\", \"host\":\"" + ipfs.host + "\", \"fileCount\":" + ipfs.refs.local().size() + "\"}"); 68 | } else if (action.equalsIgnoreCase("filelist")) { 69 | response.setStatus(HttpStatus.OK_200); 70 | String localFileList = ipfs.refs.local().stream().map(Object::toString).collect(Collectors.joining("\", \"", "[\"", "\"]")); 71 | 72 | out.print("{\"action\":\"filelist\", \"host\":\"" + ipfs.host + "\", \"file_list\":" + localFileList + "}"); 73 | } else { 74 | response.setStatus(HttpStatus.BAD_REQUEST_400); 75 | out.print("{\"action\":\"no action provided\"}"); 76 | } 77 | } 78 | 79 | @Override 80 | public void setPlatformProxy(DicooglePlatformInterface core) { 81 | this.platform = core; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/bmdsoftware/pacs/dicoogle/ipfs/services/IPFSStatusWebService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 BMD software, Lda 3 | * 4 | * This file is part of Dicoogle/ipfs. 5 | * 6 | * Dicoogle/ipfs is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Dicoogle/ipfs is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Dicoogle. If not, see . 18 | */ 19 | package com.bmdsoftware.pacs.dicoogle.ipfs.services; 20 | 21 | import io.ipfs.api.IPFS; 22 | import org.eclipse.jetty.http.HttpStatus; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | import pt.ua.dicoogle.sdk.core.DicooglePlatformInterface; 26 | import pt.ua.dicoogle.sdk.core.PlatformCommunicatorInterface; 27 | 28 | import javax.servlet.http.HttpServlet; 29 | import javax.servlet.http.HttpServletRequest; 30 | import javax.servlet.http.HttpServletResponse; 31 | import java.io.IOException; 32 | import java.io.PrintWriter; 33 | 34 | /** 35 | * IPFS Jetty Plugin - Status 36 | * 37 | * @author Luís A. Bastião Silva - 38 | * @author Eriksson Monteiro - 39 | * @author Rui Lebre - 40 | */ 41 | public class IPFSStatusWebService extends HttpServlet implements PlatformCommunicatorInterface { 42 | private static final Logger logger = LoggerFactory.getLogger(IPFSStatusWebService.class); 43 | 44 | private DicooglePlatformInterface platform; 45 | private IPFS ipfs = null; 46 | 47 | public IPFSStatusWebService(IPFS ipfs) { 48 | this.ipfs = ipfs; 49 | } 50 | 51 | @Override 52 | protected void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException { 53 | 54 | String action = req.getParameter("action"); 55 | if (action == null) { 56 | response.sendError(HttpStatus.BAD_REQUEST_400, "No action provided"); 57 | return; 58 | } 59 | response.setContentType("text/json;charset=utf-8"); 60 | PrintWriter out = response.getWriter(); 61 | 62 | if (action.equalsIgnoreCase("status")) { 63 | response.setStatus(HttpStatus.OK_200); 64 | 65 | out.print("{\"action\":\"status\", \"host\":\"" + ipfs.host + "\", \"status\":" + ipfs.stats.bw().toString() + "\"}"); 66 | } else { 67 | response.setStatus(HttpStatus.BAD_REQUEST_400); 68 | out.print("{\"action\":\"no action provided\"}"); 69 | } 70 | } 71 | 72 | @Override 73 | public void setPlatformProxy(DicooglePlatformInterface core) { 74 | this.platform = core; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/com/bmdsoftware/pacs/dicoogle/ipfs/TestIPFS.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 BMD software, Lda 3 | * 4 | * This file is part of Dicoogle/ipfs. 5 | * 6 | * Dicoogle/ipfs is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Dicoogle/ipfs is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Dicoogle. If not, see . 18 | */ 19 | package com.bmdsoftware.pacs.dicoogle.ipfs; 20 | 21 | import io.ipfs.api.IPFS; 22 | import io.ipfs.api.MerkleNode; 23 | import io.ipfs.api.NamedStreamable; 24 | import io.ipfs.multihash.Multihash; 25 | import org.junit.BeforeClass; 26 | import org.junit.Test; 27 | 28 | import java.io.*; 29 | import java.nio.charset.StandardCharsets; 30 | import java.util.Arrays; 31 | import java.util.List; 32 | import java.util.Map; 33 | import java.util.UUID; 34 | 35 | import static org.junit.Assert.assertNotNull; 36 | import static org.junit.Assert.assertTrue; 37 | 38 | /** 39 | * @author Rui Lebre - 40 | */ 41 | public class TestIPFS { 42 | private static IPFS ipfs; 43 | private static String testFileContent = "test test test"; 44 | 45 | @BeforeClass 46 | public static void setup() { 47 | ipfs = new IPFS("/ip4/127.0.0.1/tcp/5001"); 48 | } 49 | 50 | @Test 51 | public void testFileOperations() throws IOException { 52 | NamedStreamable.ByteArrayWrapper file = new NamedStreamable.ByteArrayWrapper(UUID.randomUUID().toString(), testFileContent.getBytes(StandardCharsets.UTF_8)); 53 | 54 | // Test add file 55 | MerkleNode addResult = ipfs.add(file).get(0); 56 | byte[] catResult = ipfs.cat(addResult.hash); 57 | assertTrue("Add file failed.", catResult.length > 0); 58 | 59 | 60 | // Test file content 61 | assertTrue("File content not equal.", Arrays.equals(catResult, file.getContents())); 62 | 63 | // Test file remove pin 64 | List pinRm = ipfs.pin.rm(addResult.hash, true); 65 | assertTrue("Pin removal failed.", pinRm.get(0).equals(addResult.hash)); 66 | 67 | // Test garbage collector 68 | ipfs.repo.gc(); 69 | } 70 | 71 | @Test 72 | public void testStats() throws IOException { 73 | Map stats = ipfs.stats.bw(); 74 | 75 | assertNotNull("Stats null.", stats); 76 | } 77 | 78 | @Test 79 | public void testListLocal() throws IOException { 80 | List localRefs = ipfs.refs.local(); 81 | 82 | assertNotNull("Local refs null.", localRefs); 83 | assertTrue("Local refs must be at least one.", localRefs.size() > 0); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/com/bmdsoftware/pacs/dicoogle/ipfs/TestStorage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 BMD software, Lda 3 | * 4 | * This file is part of Dicoogle/ipfs. 5 | * 6 | * Dicoogle/ipfs is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Dicoogle/ipfs is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Dicoogle. If not, see . 18 | */ 19 | package com.bmdsoftware.pacs.dicoogle.ipfs; 20 | 21 | import org.dcm4che2.data.DicomObject; 22 | import org.dcm4che2.data.Tag; 23 | import org.dcm4che2.io.DicomInputStream; 24 | import org.junit.BeforeClass; 25 | import org.junit.Test; 26 | import pt.ua.dicoogle.sdk.PluginSet; 27 | 28 | import java.io.File; 29 | import java.io.IOException; 30 | import java.io.InputStream; 31 | import java.net.URI; 32 | 33 | import static org.junit.Assert.assertEquals; 34 | 35 | /** 36 | * @author Rui Lebre - 37 | */ 38 | public class TestStorage { 39 | private static IPFSStore ipfsStorePlugin; 40 | 41 | @BeforeClass 42 | public static void setup() throws IOException { 43 | PluginSet ps = new IPFSPluginSet(); 44 | ipfsStorePlugin = (IPFSStore) ps.getStoragePlugins().toArray()[0]; 45 | } 46 | 47 | @Test 48 | public void testStorageDicomStream() throws IOException { 49 | ClassLoader classLoader = getClass().getClassLoader(); 50 | File dicomFile = new File(classLoader.getResource("DoseSR_GE_01.DCM").getPath()); 51 | 52 | // test store operation 53 | URI fileURI = ipfsStorePlugin.store(new DicomInputStream(dicomFile)); 54 | 55 | // test at operation 56 | InputStream storedDicomStream = ipfsStorePlugin.at(fileURI).iterator().next().getInputStream(); 57 | 58 | DicomObject originalDicomObj = new DicomInputStream(dicomFile).readDicomObject(); 59 | DicomObject storedDicomObj = new DicomInputStream(storedDicomStream).readDicomObject(); 60 | 61 | assertEquals(originalDicomObj.get(Tag.SOPInstanceUID), storedDicomObj.get(Tag.SOPInstanceUID)); 62 | 63 | ipfsStorePlugin.remove(fileURI); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/resources/DoseSR_GE_01.DCM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BMDSoftware/dicoogle-ipfs-storage/06c524cff66dae869237f581186bb867781b9cff/src/test/resources/DoseSR_GE_01.DCM --------------------------------------------------------------------------------