=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/AppManager.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/AppManager.java 2013-10-22 15:02:04 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/AppManager.java 2014-01-07 09:55:49 +0000 @@ -39,69 +39,78 @@ { final String ID = AppManager.class.getName(); - final String KEY_APP_FOLDER_PATH = "appFolderPath"; + final String KEY_APP_FOLDER_PATH = "appFolderPath"; final String KEY_APP_BASE_URL = "appBaseUrl"; final String KEY_APP_STORE_URL = "appStoreUrl"; final String DEFAULT_APP_STORE_URL = "http://appstore.dhis2.org"; - + /** * Gets the Base URL for accessing the apps + * * @return the apps baseurl */ String getAppBaseUrl(); - + /** * Returns the full path to the folder where apps are extracted - * @return app folder path + * + * @return app folder path */ String getAppFolderPath(); /** * Returns the url of the app repository - * @return url of appstore + * + * @return url of appstore */ String getAppStoreUrl(); /** * Returns a list of all the installed apps at @see getAppFolderPath + * * @return list of installed apps */ List getApps(); - + /** * Installs the app. - * @param file the app file. + * + * @param file the app file. * @param fileName the name of the app file. * @param rootPath the root path of the instance. * @throws IOException if the app manifest file could not be read. */ void installApp( File file, String fileName, String rootPath ) throws IOException; - + /** * Deletes the app with the given name. + * * @param name the app name. * @return true if the delete was successful, false if there is no app with - * the given name or if the app could not be removed from the file - * system. + * the given name or if the app could not be removed from the file + * system. */ boolean deleteApp( String name ); /** - * Saves the folder in which apps will be expanded + * Saves the folder in which apps will be expanded + * * @param appFolderPath */ void setAppFolderPath( String appFolderPath ); /** * Saves the URL of the apps repository + * * @param appStoreUrl */ void setAppStoreUrl( String appStoreUrl ); - + /** * Saves the base URL where apps are installed - * @param appBaseUrl + * + * @param appBaseUrl */ void setAppBaseUrl( String appBaseUrl ); } === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AppController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AppController.java 2013-10-22 15:02:04 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AppController.java 2014-01-07 09:55:49 +0000 @@ -28,35 +28,117 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import java.util.List; - +import com.fasterxml.jackson.core.type.TypeReference; +import com.google.common.collect.Lists; +import org.hisp.dhis.api.controller.exception.NotFoundException; import org.hisp.dhis.appmanager.App; import org.hisp.dhis.appmanager.AppManager; +import org.hisp.dhis.dxf2.utils.JacksonUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; +import org.springframework.util.StreamUtils; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * @author Lars Helge Overland */ @Controller -@RequestMapping( value = AppController.RESOURCE_PATH ) public class AppController { public static final String RESOURCE_PATH = "/apps"; - + @Autowired private AppManager appManager; - - @RequestMapping( method = RequestMethod.GET ) + + private ResourceLoader resourceLoader = new DefaultResourceLoader(); + + @RequestMapping( value = RESOURCE_PATH, method = RequestMethod.GET ) public String getApps( Model model ) { List apps = appManager.getApps(); - + model.addAttribute( "model", apps ); - + return "apps"; } + + @RequestMapping( value = "/apps/{app}/**", method = RequestMethod.GET ) + public void renderApp( @PathVariable( "app" ) String app, HttpServletRequest request, HttpServletResponse response ) throws IOException, NotFoundException + { + Iterable locations = Lists.newArrayList( + resourceLoader.getResource( "file:" + appManager.getAppFolderPath() + "/" + app + "/" ), + resourceLoader.getResource( "classpath*:/apps/" + app + "/" ) + ); + + Resource manifest = findResource( locations, "manifest.webapp" ); + + if ( manifest == null ) + { + throw new NotFoundException(); + } + + Map manifestMap = JacksonUtils.getJsonMapper().readValue( manifest.getInputStream(), new TypeReference>() + { + } ); + + String defaultPage = (String) manifestMap.get( "launch_path" ); + String pageName = findPage( request.getPathInfo(), app ); + + Resource page = findResource( locations, pageName ); + + if ( page == null ) + { + page = findResource( locations, defaultPage ); + + if ( page == null ) + { + throw new NotFoundException(); + } + } + + String mimeType = request.getSession().getServletContext().getMimeType( page.getFilename() ); + response.setContentType( mimeType ); + + StreamUtils.copy( page.getInputStream(), response.getOutputStream() ); + } + + private Resource findResource( Iterable locations, String resourceName ) throws IOException + { + for ( Resource location : locations ) + { + Resource resource = location.createRelative( resourceName ); + + if ( resource.exists() && resource.isReadable() ) + { + return resource; + } + } + + return null; + } + + private String findPage( String path, String app ) + { + String prefix = RESOURCE_PATH + "/" + app + "/"; + + if ( path.startsWith( prefix ) ) + { + path = path.substring( prefix.length() ); + } + + return path; + } }