001    package net.abriraqui.dm4.importexport;
002    
003    import de.deepamehta.core.osgi.PluginActivator;
004    import de.deepamehta.core.util.JavaUtils;
005    import de.deepamehta.core.util.DeepaMehtaUtils;
006    import de.deepamehta.core.service.PluginService;
007    import de.deepamehta.core.service.Plugin;
008    import de.deepamehta.core.service.annotation.ConsumesService;
009    import de.deepamehta.core.Topic;
010    import de.deepamehta.core.TopicType;
011    import de.deepamehta.core.ViewConfiguration;
012    import de.deepamehta.core.Association;
013    import de.deepamehta.core.model.TopicModel;
014    import de.deepamehta.core.model.CompositeValueModel;
015    import de.deepamehta.core.model.AssociationModel;
016    import de.deepamehta.core.model.RoleModel;
017    import de.deepamehta.core.model.SimpleValue;
018    import de.deepamehta.core.storage.spi.DeepaMehtaTransaction;
019    
020    import de.deepamehta.plugins.topicmaps.service.TopicmapsService;
021    import de.deepamehta.plugins.topicmaps.model.TopicmapViewmodel;
022    import de.deepamehta.plugins.topicmaps.model.TopicViewmodel;
023    import de.deepamehta.plugins.topicmaps.model.AssociationViewmodel;
024    
025    import de.deepamehta.plugins.files.service.FilesService;
026    import de.deepamehta.plugins.files.UploadedFile;
027    
028    import javax.xml.stream.XMLStreamException;
029    import javax.xml.stream.XMLStreamWriter;
030    import javax.xml.stream.XMLOutputFactory;
031    import javax.xml.transform.OutputKeys;
032    import javax.xml.bind.DatatypeConverter;
033    
034    import java.io.Writer;
035    import java.io.FileWriter;
036    import java.io.File;
037    import java.io.FileInputStream;
038    import java.io.InputStream;
039    import java.io.InputStreamReader;
040    import java.io.ByteArrayInputStream;
041    import java.io.ByteArrayOutputStream;
042    import java.io.IOException;
043    import java.io.BufferedInputStream;
044    import java.io.BufferedReader;
045    import java.io.DataInputStream;
046    
047    import java.util.logging.Logger;
048    import java.util.Map;
049    import java.util.HashMap;
050    import java.util.List;
051    import java.util.ArrayList;
052    
053    import org.codehaus.jettison.json.JSONObject;
054    import org.codehaus.jettison.json.JSONArray;
055    import org.codehaus.jettison.json.JSONException;
056    
057    import javax.ws.rs.POST;
058    import javax.ws.rs.Path;
059    import javax.ws.rs.Produces;
060    import javax.ws.rs.Consumes;
061    import javax.ws.rs.CookieParam;
062    import javax.ws.rs.core.MediaType;
063    
064    import com.sun.jersey.core.util.Base64;
065    
066    
067    @Path("/import-export")
068    @Produces("application/json")
069    public class ImportExportPlugin extends PluginActivator {
070        
071        private TopicmapsService topicmapsService;
072        private FilesService filesService;
073    
074        private Logger log = Logger.getLogger(getClass().getName());
075    
076        // Service implementation //
077    
078        @POST
079        @Path("/export/json")
080        public Topic exportTopicmapToJSON(@CookieParam("dm4_topicmap_id") long topicmapId) {
081    
082            try {
083                log.info("Exporting topicmap #########" + topicmapId);
084                TopicmapViewmodel topicmap = topicmapsService.getTopicmap(topicmapId, true);
085                String json = topicmap.toJSON().toString();
086                InputStream in = new ByteArrayInputStream(json.getBytes("UTF-8"));
087                Topic createdFile = filesService.createFile(in, "/topicmap-" + topicmapId + ".txt");
088                return createdFile;
089            } catch (Exception e) {
090                throw new RuntimeException("Export failed", e );
091            } 
092        }
093    
094    
095    
096        @POST
097        @Path("/export/svg")
098        public void exportTopicmapToSVG(@CookieParam("dm4_topicmap_id") long topicmapId)  throws XMLStreamException {
099            try {
100                final int BOX_HEIGHT = 20;
101                final int MARGIN_LEFT = 5;
102                final int MARGIN_TOP = 14;
103                final int ICON_WIDTH = 16;
104                final int ICON_HEIGHT = 16;
105    
106                log.info("Exporting topicmap #########" + topicmapId);
107                TopicmapViewmodel topicmap = topicmapsService.getTopicmap(topicmapId, true);
108                Iterable<TopicViewmodel> topics =topicmap.getTopics();
109                Iterable<AssociationViewmodel> associations = topicmap.getAssociations();
110    
111                String SVGfileName = "ExportedTopicamap-" + topicmapId +".svg";
112                SVGRenderer svg = new SVGRenderer(SVGfileName);
113    
114                for (AssociationViewmodel association : associations) {
115                    String valueAssoc= association.getSimpleValue().toString();
116                    long topic1Id = association.getRoleModel1().getPlayerId();
117                    long topic2Id = association.getRoleModel2().getPlayerId();
118                    TopicViewmodel topic1 = topicmap.getTopic(topic1Id);
119                    int x1 = topic1.getX();
120                    int y1 = topic1.getY();
121    
122                    TopicViewmodel topic2 = topicmap.getTopic(topic2Id);
123                    int x2 = topic2.getX();
124                    int y2 = topic2.getY();
125    
126                    int dx = x2-x1;
127                    int dy = y2-y1;
128                    int label_x = dx/2;
129                    int label_y = dy/2;
130                    double assocLine = Math.sqrt(Math.pow(dx,2)+Math.pow(dy,2));
131                    double alpha = Math.asin(dy/assocLine)*180/Math.PI;
132                    if (dx < 0) {
133                        alpha = -alpha;
134                        }
135                    
136                    svg.line(x1, x2, y1, y2);
137                    svg.text(label_x, label_y,x1+10,y1+10, valueAssoc, "grey", alpha);
138    
139                }
140    
141    
142                for (TopicViewmodel topic : topics) {
143                    String value= topic.getSimpleValue().toString();
144                    int x = topic.getX();
145                    int y = topic.getY();
146                    boolean visibility = topic.getVisibility();
147                    int boxWidth = value.length() * 9;
148    
149                    if (!visibility) { continue ;}
150                    svg.rectangle(x - boxWidth / 2, y - BOX_HEIGHT / 2, boxWidth, BOX_HEIGHT, color(topic.getTypeUri()));
151                    svg.text(x - boxWidth / 2 + MARGIN_LEFT, y - BOX_HEIGHT / 2 + MARGIN_TOP, value, "black");
152                    svg.image(x + boxWidth / 2, y, ICON_WIDTH, ICON_HEIGHT, typeIconDataUri(topic.getTypeUri()));
153                }
154                
155    
156                svg.closeDocument();
157    
158            } catch (Exception e) {
159                throw new RuntimeException("Export failed", e );
160            } 
161        }
162    
163    
164    
165        @POST
166        @Path("/import")
167        @Consumes("multipart/form-data")
168        public Topic importTopicmap(UploadedFile file) {
169            try {
170                String json = file.getString();
171    
172                JSONObject topicmap = new JSONObject(json);
173                JSONObject info = topicmap.getJSONObject("info");
174    
175                JSONArray assocsArray = topicmap.getJSONArray("assocs");
176                JSONArray topicsArray = topicmap.getJSONArray("topics");
177              
178                String origTopicmapName = info.getString("value");
179                Topic importedTopicmap = topicmapsService.createTopicmap("Imported Topicmap: "+ origTopicmapName,"dm4.webclient.default_topicmap_renderer", null);
180    
181                long topicmapId = importedTopicmap.getId();
182                log.info("###### importedTopicapId " + topicmapId);
183    
184                Map<Long, Long> mapTopicIds = new HashMap();
185                importTopics(topicsArray, mapTopicIds, topicmapId);
186                importAssociations(assocsArray,mapTopicIds, topicmapId);
187                return importedTopicmap;        
188            } catch (Exception e) {
189                throw new RuntimeException("Importing failed", e);
190            }
191        }
192    
193                
194                // Import topics
195                
196        private void importTopics(JSONArray topicsArray, Map<Long, Long> mapTopicIds, long topicmapId) {
197            for (int i = 0, size = topicsArray.length(); i < size; i++)  {
198                try {
199                    JSONObject topic =  topicsArray.getJSONObject(i);
200                    createTopic(topic, mapTopicIds, topicmapId);
201                } catch (Exception e){
202                    log.warning("Topic not imported!!" + e);
203                }
204            }
205        }
206                // Import associations
207    
208        private void importAssociations(JSONArray assocsArray, Map<Long, Long> mapTopicIds, long topicmapId) {
209            for (int i=0, size = assocsArray.length(); i< size; i++) {               
210                try {
211                    JSONObject association = assocsArray.getJSONObject(i);
212                    createAssociation(association, mapTopicIds, topicmapId);
213                } catch (Exception e) {
214                    log.warning("Association not imported");
215                }
216            }
217        }
218        
219    
220    
221    
222        // Hook implementation //
223        
224        @Override
225        @ConsumesService({TopicmapsService.class, FilesService.class })
226        public void serviceArrived(PluginService service) {
227            if (service instanceof TopicmapsService) {
228                topicmapsService = (TopicmapsService) service;
229            } else if (service instanceof FilesService) {
230                filesService = (FilesService) service;
231            }
232        }
233       
234        @Override
235        public void serviceGone(PluginService service) {
236            if (service == topicmapsService) {
237                topicmapsService = null;
238            } else if (service == filesService) {
239                filesService = null;
240            }
241        }
242    
243        
244        private String color(String typeUri) {
245            if (typeUri.equals("dm4.contacts.institution")) {
246                return "lightblue";
247            } else if (typeUri.equals("dm4.contacts.person")) {
248                return "lightblue";
249            } else if (typeUri.equals("dm4.notes.note")) {
250                return "lightblue";
251            } else {
252                return "lightblue";
253            }
254        }
255    
256    
257        private String typeIconDataUri(String typeUri) throws IOException {
258            TopicType topicType = dms.getTopicType(typeUri);
259            String iconPath = (String) topicType.getViewConfig("dm4.webclient.view_config","dm4.webclient.icon");
260            int sep = iconPath.indexOf("/", 2);
261            String pluginPath = iconPath.substring(1, sep);
262            Plugin plugin = dms.getPlugin(pluginPath);
263            String imagePath = "web"+iconPath.substring(sep);
264            
265            InputStream iconIS = plugin.getResourceAsStream(imagePath);
266            ByteArrayOutputStream baos = new ByteArrayOutputStream();
267            byte [] buffer = new byte[1024];
268            int count = 0;
269            while ( (count = iconIS.read(buffer)) != -1 ) {
270                baos.write(buffer, 0, count);
271            }
272    
273            byte [] fileContent = baos.toByteArray();
274            //all chars in encoded are guaranteed to be 7-bit ASCII
275            byte[] encoded = Base64.encode(fileContent);
276            String imgBase64Str = new String(encoded);
277            log.info("##### IMG BASE64 " + imgBase64Str);
278            
279            if (iconPath == null) {
280                iconPath = "/de.deepamehta.webclient/images/ball-gray.png";
281            }
282    
283            return "data:image/png;base64," + imgBase64Str;
284                     
285       }
286    
287      
288        private void createTopic(JSONObject topic, Map<Long, Long> mapTopicIds, long topicmapId) throws JSONException {
289            TopicModel model = new TopicModel(topic);
290            CompositeValueModel viewProps =new CompositeValueModel(topic.getJSONObject("view_props")); 
291            long origTopicId = model.getId();
292            
293            Topic newTopic = dms.createTopic(model, null);
294            long topicId = newTopic.getId();
295            
296            mapTopicIds.put(origTopicId, topicId);
297            topicmapsService.addTopicToTopicmap(topicmapId, topicId, viewProps);
298        }
299        
300        private void createAssociation(JSONObject association, Map<Long, Long> mapTopicIds, long topicmapId) {
301            AssociationModel assocModel = new AssociationModel(association);                
302            RoleModel role1 = assocModel.getRoleModel1();
303            role1.setPlayerId(mapTopicIds.get(role1.getPlayerId()));
304            RoleModel role2 = assocModel.getRoleModel2();
305            role2.setPlayerId(mapTopicIds.get(role2.getPlayerId()));
306            Association newAssociation = dms.createAssociation(assocModel, null);
307            long assocId = newAssociation.getId();
308            topicmapsService.addAssociationToTopicmap(topicmapId, assocId);          
309            
310        }
311    
312    }
313