001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.isis.core.metamodel.services.devutils; 020 021import java.io.ByteArrayOutputStream; 022import java.io.File; 023import java.io.IOException; 024import java.io.OutputStreamWriter; 025import java.util.Collection; 026import java.util.Collections; 027import java.util.List; 028import java.util.zip.ZipEntry; 029import java.util.zip.ZipOutputStream; 030import javax.activation.MimeType; 031import javax.activation.MimeTypeParseException; 032import com.google.common.base.Predicate; 033import com.google.common.collect.Collections2; 034import com.google.common.collect.Lists; 035import org.apache.isis.applib.FatalException; 036import org.apache.isis.applib.annotation.Programmatic; 037import org.apache.isis.applib.services.devutils.DeveloperUtilitiesService; 038import org.apache.isis.applib.value.Blob; 039import org.apache.isis.applib.value.Clob; 040import org.apache.isis.core.metamodel.adapter.ObjectAdapter; 041import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager; 042import org.apache.isis.core.metamodel.adapter.mgr.AdapterManagerAware; 043import org.apache.isis.core.metamodel.layoutmetadata.json.LayoutMetadataReaderFromJson; 044import org.apache.isis.core.metamodel.spec.ObjectSpecification; 045import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi; 046import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpiAware; 047import org.apache.isis.core.metamodel.spec.feature.*; 048 049public class DeveloperUtilitiesServiceDefault implements DeveloperUtilitiesService, SpecificationLoaderSpiAware, AdapterManagerAware { 050 051 052 private final MimeType mimeTypeTextCsv; 053 private final MimeType mimeTypeApplicationZip; 054 private final MimeType mimeTypeApplicationJson; 055 056 public DeveloperUtilitiesServiceDefault() { 057 try { 058 mimeTypeTextCsv = new MimeType("text", "csv"); 059 mimeTypeApplicationJson = new MimeType("application", "jzon"); 060 mimeTypeApplicationZip = new MimeType("application", "zip"); 061 } catch (MimeTypeParseException e) { 062 throw new RuntimeException(e); 063 } 064 } 065 066 // ////////////////////////////////////// 067 068 069 @Override 070 public Clob downloadMetaModel() { 071 072 final Collection<ObjectSpecification> specifications = specificationLoader.allSpecifications(); 073 074 final List<MetaModelRow> rows = Lists.newArrayList(); 075 for (ObjectSpecification spec : specifications) { 076 if (exclude(spec)) { 077 continue; 078 } 079 final List<ObjectAssociation> properties = spec.getAssociations(Contributed.EXCLUDED, ObjectAssociation.Filters.PROPERTIES); 080 for (ObjectAssociation property : properties) { 081 final OneToOneAssociation otoa = (OneToOneAssociation) property; 082 if (exclude(otoa)) { 083 continue; 084 } 085 rows.add(new MetaModelRow(spec, otoa)); 086 } 087 final List<ObjectAssociation> associations = spec.getAssociations(Contributed.EXCLUDED, ObjectAssociation.Filters.COLLECTIONS); 088 for (ObjectAssociation collection : associations) { 089 final OneToManyAssociation otma = (OneToManyAssociation) collection; 090 if (exclude(otma)) { 091 continue; 092 } 093 rows.add(new MetaModelRow(spec, otma)); 094 } 095 final List<ObjectAction> actions = spec.getObjectActions(Contributed.INCLUDED); 096 for (ObjectAction action : actions) { 097 if (exclude(action)) { 098 continue; 099 } 100 rows.add(new MetaModelRow(spec, action)); 101 } 102 } 103 104 Collections.sort(rows); 105 106 final StringBuilder buf = new StringBuilder(); 107 buf.append(MetaModelRow.header()).append("\n"); 108 for (MetaModelRow row : rows) { 109 buf.append(row.asTextCsv()).append("\n"); 110 } 111 return new Clob("metamodel.csv", mimeTypeTextCsv, buf.toString().toCharArray()); 112 } 113 114 protected boolean exclude(OneToOneAssociation property) { 115 return false; 116 } 117 118 protected boolean exclude(OneToManyAssociation collection) { 119 return false; 120 } 121 122 protected boolean exclude(ObjectAction action) { 123 return false; 124 } 125 126 protected boolean exclude(ObjectSpecification spec) { 127 return isBuiltIn(spec) || spec.isAbstract(); 128 } 129 130 protected boolean isBuiltIn(ObjectSpecification spec) { 131 final String className = spec.getFullIdentifier(); 132 return className.startsWith("java") || className.startsWith("org.joda"); 133 } 134 135 // ////////////////////////////////////// 136 137 @Override 138 public void refreshServices() { 139 Collection<ObjectSpecification> specifications = Lists.newArrayList(specificationLoader.allSpecifications()); 140 for (ObjectSpecification objectSpec : specifications) { 141 if(objectSpec.isService()){ 142 specificationLoader.invalidateCache(objectSpec.getCorrespondingClass()); 143 } 144 } 145 } 146 147 // ////////////////////////////////////// 148 149 @Override 150 public Object refreshLayout(Object domainObject) { 151 specificationLoader.invalidateCacheFor(domainObject); 152 return domainObject; 153 } 154 155 // ////////////////////////////////////// 156 157 @Override 158 public Clob downloadLayout(Object domainObject) { 159 160 final ObjectAdapter adapterFor = adapterManager.adapterFor(domainObject); 161 final ObjectSpecification objectSpec = adapterFor.getSpecification(); 162 163 final LayoutMetadataReaderFromJson propertiesReader = new LayoutMetadataReaderFromJson(); 164 final String json = propertiesReader.asJson(objectSpec); 165 166 return new Clob(objectSpec.getShortIdentifier() +".layout.json", mimeTypeApplicationJson, json); 167 } 168 169 // ////////////////////////////////////// 170 171 @Override 172 public Blob downloadLayouts() { 173 final LayoutMetadataReaderFromJson propertiesReader = new LayoutMetadataReaderFromJson(); 174 final Collection<ObjectSpecification> allSpecs = specificationLoader.allSpecifications(); 175 final Collection<ObjectSpecification> domainObjectSpecs = Collections2.filter(allSpecs, new Predicate<ObjectSpecification>(){ 176 @Override 177 public boolean apply(ObjectSpecification input) { 178 return !input.isAbstract() && 179 !input.isService() && 180 !input.isValue() && 181 !input.isParentedOrFreeCollection(); 182 }}); 183 try { 184 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 185 ZipOutputStream zos = new ZipOutputStream(baos); 186 OutputStreamWriter writer = new OutputStreamWriter(zos); 187 for (ObjectSpecification objectSpec : domainObjectSpecs) { 188 zos.putNextEntry(new ZipEntry(zipEntryNameFor(objectSpec))); 189 writer.write(propertiesReader.asJson(objectSpec)); 190 writer.flush(); 191 zos.closeEntry(); 192 } 193 writer.close(); 194 return new Blob("layouts.zip", mimeTypeApplicationZip, baos.toByteArray()); 195 } catch (final IOException ex) { 196 throw new FatalException("Unable to create zip of layouts", ex); 197 } 198 } 199 200 private static String zipEntryNameFor(ObjectSpecification objectSpec) { 201 final String fqn = objectSpec.getFullIdentifier(); 202 return fqn.replace(".", File.separator)+".layout.json"; 203 } 204 205 206 // ////////////////////////////////////// 207 208 private SpecificationLoaderSpi specificationLoader; 209 private AdapterManager adapterManager; 210 211 @Programmatic 212 @Override 213 public void setSpecificationLoaderSpi(SpecificationLoaderSpi specificationLoader) { 214 this.specificationLoader = specificationLoader; 215 } 216 217 @Override 218 public void setAdapterManager(AdapterManager adapterManager) { 219 this.adapterManager = adapterManager; 220 } 221 222 223}