Commit 2ed41202 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '205-cdn-with-cloudfront' into 'master'

Resolve "CDN with Cloudfront"

Closes #205 and #204

See merge request genesys-pgr/genesys-server!105
parents 27540bcf e669c2a3
......@@ -135,7 +135,7 @@ module.exports = function(grunt) {
'bower_components/tinymce/tinymce.jquery.js', 'bower_components/tinymce/themes/modern/theme.js', 'bower_components/tinymce/plugins/link/plugin.js',
'bower_components/tinymce/plugins/autolink/plugin.js', 'bower_components/tinymce/plugins/code/plugin.js', 'bower_components/leaflet/dist/leaflet.js',
'bower_components/leaflet-locationfilter/src/locationfilter.js', 'bower_components/bootstrap-sass/assets/javascripts/bootstrap.js', 'bower_components/jquery-ui/jquery-ui.js',
'bower_components/jquery-ui/ui/autocomplete.js', 'bower_components/dyn-css/lib/dyncss.js', 'bower_components/jstree/dist/jstree.min.js' ],
'bower_components/jquery-ui/ui/autocomplete.js', 'bower_components/jstree/dist/jstree.min.js' ],
dest : '<%= app.dist1 %>/js/libraries.js',
},
app1 : {
......
......@@ -13,7 +13,6 @@
"jquery.tinymce": "*",
"bootstrap-sass": "~3.3.6",
"jquery-ui": "~1.11.4",
"dyn-css": "~0.8.1",
"webfont-notosans": "~0.1.0",
"fontawesome": "~4.4.0",
"highcharts": "~4.1.8",
......
......@@ -6,8 +6,8 @@ services:
environment:
- spring.profiles.active=dev
- JAVA_OPTIONS=-Xms1800M -Xmx1800M -server -Dnetworkaddress.cache.ttl=10
- base.host=${CI_ENVIRONMENT_SLUG}.review.genesys-pgr.org
- base.hostname=${CI_ENVIRONMENT_SLUG}.review.genesys-pgr.org
- host.name=${CI_ENVIRONMENT_SLUG}.review.genesys-pgr.org
- base.url=https://${CI_ENVIRONMENT_SLUG}.review.genesys-pgr.org
- robots.allow=false
- db.url=jdbc:hsqldb:mem:genesys;sql.syntax_mys=true
- db.driverClassName=org.hsqldb.jdbc.JDBCDriver
......
......@@ -55,9 +55,7 @@ cookies between all .genesys-pgr.org domains.
plan to run on HTTPS protocol.
|base.cookie-http-only|false|AJAX calls from the browser sometimes require session information for
user authentication. Keep this value `false`.
|cdn.server|${base.url}|Default configuration does not use a CDN and defaults to the `base.url`.
|cdn.base|${cdn.server}|
|cdn.flags.url|${cdn.base}/html/0/images/flags|
|cdn.servers|${base.url}|Default configuration does not use a CDN and defaults to the `base.url`.
|robots.allow|false|Setting this to `true` will produce a `/robots.txt` response that allows robots to index
the site.
|===
......@@ -225,11 +223,6 @@ Genesys uses a number of external service APIs to provide users with advanced fu
theme.defaultThemeName=dev
# TileServer CDN
#tileserver.cdn='https://s1'
#tileserver.cdn='https://s1.cdn.genesys-pgr.org','https://s2.cdn.genesys-pgr.org','https://s3.cdn.genesys-pgr.org','https://s4.cdn.genesys-pgr.org'
tileserver.cdn='${base.url}'
# TileServer Cache
cache.defaultCacheSize=5000
cache.tileserver.max-size=1000
......
/*
* Copyright 2016 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.genesys2.server.config;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* This class provides application properties on JSP pages
*/
@Component("props")
public class ApplicationProps implements InitializingBean {
@Value("${tileserver.cdn}")
private String tileserverCdn;
@Value("${cdn.server}")
private String cdnServer;
@Value("${base.url}")
private String baseUrl;
public String getTileserverCdn() {
return tileserverCdn;
}
@Override
public void afterPropertiesSet() throws Exception {
}
public String getCdnServer() {
return this.cdnServer;
}
public String getBaseUrl() {
return baseUrl;
}
}
......@@ -108,7 +108,7 @@ public class MappingServiceImpl implements MappingService {
final ObjectNode geoJson = mapper.createObjectNode();
geoJson.put("type", "FeatureCollection");
final ArrayNode featuresArray = geoJson.arrayNode();
geoJson.put("features", featuresArray);
geoJson.set("features", featuresArray);
filterService.listGeo(filters, limit, new RowCallbackHandler() {
@Override
......@@ -119,16 +119,16 @@ public class MappingServiceImpl implements MappingService {
feature.put("id", rs.getLong("id"));
ObjectNode geometry;
feature.put("geometry", geometry = feature.objectNode());
feature.set("geometry", geometry = feature.objectNode());
geometry.put("type", "Point");
ArrayNode coordArray;
geometry.put("coordinates", coordArray = geometry.arrayNode());
geometry.set("coordinates", coordArray = geometry.arrayNode());
coordArray.add(rs.getDouble("longitude"));
coordArray.add(rs.getDouble("latitude"));
ObjectNode properties;
feature.put("properties", properties = feature.objectNode());
feature.set("properties", properties = feature.objectNode());
properties.put("acceNumb", rs.getString("acceNumb"));
properties.put("instCode", rs.getString("instCode"));
properties.put("datum", rs.getString("datum"));
......
......@@ -80,6 +80,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.facet.result.Term;
import org.springframework.data.elasticsearch.core.facet.result.TermResult;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
......@@ -829,6 +830,8 @@ public class ExplorerController extends BaseController implements InitializingBe
byte[] image = mappingService.getTile(appliedFilters, zoom, x, y);
image = changeColor(color, image);
response.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=3600, s-maxage=3600, public, no-transform");
response.getOutputStream().write(image, 0, image.length);
} catch (final IOException e) {
......
......@@ -71,7 +71,7 @@ public class RepositoryDownloadController extends BaseController {
data = this.repositoryService.getFileBytes(repositoryFile.getStoragePath(), repositoryFile.getFilename());
response.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=3600, s-maxage=3600, public, no-transform");
response.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=86400, s-maxage=86400, public, no-transform");
response.setHeader(HttpHeaders.PRAGMA, "");
response.setDateHeader(HttpHeaders.LAST_MODIFIED, repositoryFile.getLastModifiedDate().getTime());
response.setContentType(repositoryFile.getContentType());
......
/**
* Copyright 2014 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package org.genesys2.server.servlet.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
@Component("envVarFilter")
public class EnvVariablesFilter extends OncePerRequestFilter {
@Value("${google.analytics.account}")
private String googleAnalyticsAccount;
@Value("${cdn.flags.url}")
private String cdnFlagsUrl;
@Value("${base.url}")
private String baseUrl;
@Override
public void afterPropertiesSet() throws ServletException {
super.afterPropertiesSet();
cdnFlagsUrl = StringUtils.defaultIfBlank(cdnFlagsUrl, null);
googleAnalyticsAccount = StringUtils.defaultIfBlank(googleAnalyticsAccount, null);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (googleAnalyticsAccount != null) {
request.setAttribute("googleAnalyticsAccount", googleAnalyticsAccount);
}
if (cdnFlagsUrl != null) {
request.setAttribute("cdnFlagsUrl", cdnFlagsUrl);
}
if (baseUrl != null) {
request.setAttribute("baseUrl", baseUrl);
}
filterChain.doFilter(request, response);
}
}
......@@ -19,14 +19,18 @@ package org.genesys2.spring;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.BeanCreationException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class AddStuffInterceptor implements HandlerInterceptor {
public class AddStuffInterceptor implements HandlerInterceptor, InitializingBean {
// @Autowired
// private RequestTracker requestTracker;
......@@ -37,31 +41,75 @@ public class AddStuffInterceptor implements HandlerInterceptor {
@Value("${build.revision}")
private String buildRevision;
@Value("${cdn.servers}")
private String[] cdnServers;
@Value("${base.url}")
private String baseUrl;
@Value("${google.analytics.account}")
private String googleAnalyticsAccount;
public abstract interface RandomString {
/// Get a random CDN server
public String getNext();
/// Return all CDN servers in a JS array
public String getServerList();
}
private RandomString randomCdnServer;
@Override
public void afterPropertiesSet() throws Exception {
googleAnalyticsAccount = StringUtils.defaultIfBlank(googleAnalyticsAccount, null);
final String allCdnJs = new ObjectMapper().writeValueAsString(cdnServers);
randomCdnServer = new RandomString() {
@Override
public String getNext() {
return cdnServers[RandomUtils.nextInt(cdnServers.length)];
}
@Override
public String getServerList() {
return allCdnJs;
}
};
}
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView modelAndView) throws Exception {
final long startTime = (Long) arg0.getAttribute("springStartTime");
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView modelAndView) throws Exception {
final long startTime = (Long) request.getAttribute("springStartTime");
final long endTime = System.currentTimeMillis();
final long executeTime = endTime - startTime;
arg0.setAttribute("springExecuteTime", executeTime);
request.setAttribute("springExecuteTime", executeTime);
try {
// arg0.setAttribute("lastGet", requestTracker.getLastGet());
} catch (BeanCreationException e) {
// No requestTracker bean
}
// try {
// // arg0.setAttribute("lastGet", requestTracker.getLastGet());
// } catch (BeanCreationException e) {
// // No requestTracker bean
// }
}
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
final long startTime = System.currentTimeMillis();
arg0.setAttribute("springStartTime", startTime);
arg0.setAttribute("buildName", buildName);
arg0.setAttribute("buildRevision", buildRevision);
request.setAttribute("springStartTime", startTime);
request.setAttribute("buildName", buildName);
request.setAttribute("buildRevision", buildRevision);
request.setAttribute("cdnServers", randomCdnServer);
request.setAttribute("baseUrl", baseUrl);
if (googleAnalyticsAccount != null) {
request.setAttribute("googleAnalyticsAccount", googleAnalyticsAccount);
}
return true;
}
......
......@@ -83,6 +83,9 @@ public class WebConfiguration extends WebMvcConfigurerAdapter {
@Resource
private Set<String> supportedLocales;
@Value("${base.url}")
private String baseUrl;
@Scope("singleton")
@Bean
@Override
......@@ -109,7 +112,7 @@ public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/html/**").addResourceLocations("/html/").setCacheControl(CacheControl.maxAge(42, TimeUnit.DAYS).cachePrivate());
registry.addResourceHandler("/html/**").addResourceLocations("/html/").setCacheControl(CacheControl.maxAge(1, TimeUnit.DAYS).cachePublic());
registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
......@@ -133,7 +136,7 @@ public class WebConfiguration extends WebMvcConfigurerAdapter {
resolver.setPrefix("/WEB-INF/jsp");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
resolver.setExposedContextBeanNames(new String[] { "props", "jspHelper" });
resolver.setExposedContextBeanNames(new String[] { "jspHelper" });
resolver.setRedirectHttp10Compatible(false);
resolver.setRequestContextAttribute("requestContext");
resolver.setViewClass(JstlView.class);
......
......@@ -113,12 +113,6 @@ public class WebInitializer extends AbstractAnnotationConfigDispatcherServletIni
localeURLFilter.setInitParameter("allowed-locales", "en es de fr fa ar ru zh pt");
localeURLFilter.addMappingForUrlPatterns(null, false, "/*");
// EnvVar filter configuration
// Adds variables to all requests
// TODO Upgrade to @WebFilter
final FilterRegistration.Dynamic envVarFilter = servletContext.addFilter("envVarFilter", new DelegatingFilterProxy("envVarFilter"));
envVarFilter.addMappingForUrlPatterns(null, false, "/*");
// http://stackoverflow.com/a/22409634
final ConfigurableSiteMeshFilter sitemeshWithErrors = new ConfigurableSiteMeshFilter() {
@Override
......
......@@ -14,6 +14,15 @@
# limitations under the License.
#-------------------------------------------------------------------------------
# Key configuration
host.name=localhost
base.url=http://${host.name}:8080
cdn.servers=${base.url}
base.cookie-domain=${host.name}
base.cookie-secure=false
base.cookie-http-only=true
#Paginator
paginator.default.maxPageSize=500
paginator.default.pageSize=50
......@@ -31,15 +40,6 @@ build.artifactId=${project.artifactId}
build.name=${project.artifactId}-${buildNumber}
build.revision=${buildNumber}
base.host=localhost
base.hostname=${base.host}:8080
host.name=${base.hostname}
base.url=http://${base.hostname}
base.cookie-domain=${base.host}
base.cookie-secure=false
base.cookie-http-only=true
# robots.txt
robots.allow=false
......@@ -78,12 +78,6 @@ itpgrfa.easysmta.password=foo
# GA Account
google.analytics.account=
# CDN
cdn.server=${base.url}
cdn.base=${cdn.server}
cdn.flags.url=${cdn.base}/html/1/images/flags
# Content creation on startup
auto.createContent=false
......@@ -148,11 +142,6 @@ theme.defaultThemeName=dev
scheduler.tokens.cleanup.hours=1
# TileServer CDN
#tileserver.cdn='https://s1'
#tileserver.cdn='https://s1.cdn.genesys-pgr.org','https://s2.cdn.genesys-pgr.org','https://s3.cdn.genesys-pgr.org','https://s4.cdn.genesys-pgr.org'
tileserver.cdn='${base.url}'
# Cache configuration
cache.defaultCacheSize=2000
cache.eviction-policy=LRU
......
......@@ -2,17 +2,16 @@
<c:choose>
<c:when test="${requestContext.theme.name eq 'one'}">
<link href="<c:url value="/html/1/styles/all.min.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="${cdnServers.next}/html/1/styles/all.min.css" />" type="text/css" rel="stylesheet" />
</c:when>
<c:when test="${requestContext.theme.name eq 'all'}">
<link href="<c:url value="/html/1/styles/bootstrap.min.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="/html/1/styles/other.min.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="/html/1/styles/genesys.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="${cdnServers.next}/html/1/styles/bootstrap.min.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="${cdnServers.next}/html/1/styles/other.min.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="${cdnServers.next}/html/1/styles/genesys.css" />" type="text/css" rel="stylesheet" />
</c:when>
<c:otherwise>
<link href="<c:url value="/html/1/styles/bootstrap.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="/html/1/styles/other.min.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="/html/1/styles/genesys.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="${cdnServers.next}/html/1/styles/bootstrap.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="${cdnServers.next}/html/1/styles/other.min.css" />" type="text/css" rel="stylesheet" />
<link href="<c:url value="${cdnServers.next}/html/1/styles/genesys.css" />" type="text/css" rel="stylesheet" />
</c:otherwise>
</c:choose>
......@@ -44,7 +44,7 @@
</ul>
<div class="text-center" id="copyright">
<p>
<spring:message code="footer.copyright-statement" arguments='<%= new SimpleDateFormat("YYYY").format(new Date()) %>' htmlEscape="false" />
<spring:message code="footer.copyright-statement" arguments="2017" htmlEscape="false" />
</p>
</div>
</div>
......@@ -60,20 +60,20 @@
<%-- Placed at the end of the document so the pages load faster --%>
<c:choose>
<c:when test="${requestContext.theme.name eq 'one'}">
<script type="text/javascript" src="<c:url value="/html/1/js/all.min.js" />"></script>
<script type="text/javascript" src="<c:url value="${cdnServers.next}/html/1/js/all.min.js" />"></script>
</c:when>
<c:when test="${requestContext.theme.name eq 'all'}">
<script type="text/javascript" src="<c:url value="/html/1/js/libraries.min.js" />"></script>
<script type="text/javascript" src="<c:url value="/html/1/js/genesys.js" />"></script>
<script type="text/javascript" src="<c:url value="${cdnServers.next}/html/1/js/libraries.min.js" />"></script>
<script type="text/javascript" src="<c:url value="${cdnServers.next}/html/1/js/genesys.js" />"></script>
</c:when>
<c:otherwise>
<script type="text/javascript" src="<c:url value="/html/1/js/libraries.js" />"></script>
<script type="text/javascript" src="<c:url value="/html/1/js/genesys.js" />"></script>
<script type="text/javascript" src="<c:url value="${cdnServers.next}/html/1/js/libraries.js" />"></script>
<script type="text/javascript" src="<c:url value="${cdnServers.next}/html/1/js/genesys.js" />"></script>
</c:otherwise>
</c:choose>
<script type="text/javascript">
L.Icon.Default.imagePath = '<c:url value="/html/1/styles/images" />';
L.Icon.Default.imagePath = '<c:url value="${cdnServers.next}/html/1/styles/images" />';
<%--dynCss.config.debug=true;--%>
//enableSessionWarning(${pageContext.session.maxInactiveInterval});
</script>
......
......@@ -18,7 +18,7 @@
<meta name="_csrf_header" content="${_csrf.headerName}" />
<!-- Links -->
<link rel="shortcut icon" href="<c:url value="/html/1/images/genesys.png" />" />
<link rel="shortcut icon" href="<c:url value="${cdnServers.next}/html/1/images/genesys.png" />" />
<!-- opensearch.org -->
<link rel="search" hreflang="${pageContext.response.locale.language}" type="application/opensearchdescription+xml" href="<c:url value="/acn/opensearch/desc" />"
......
......@@ -418,9 +418,9 @@
<div class="section-inner-content clearfix">
<div class="row imagegallery thumbs" id="accession-images-thumbs">
<c:forEach items="${imageGallery.images}" var="image">
<div x-uuid="<c:out value=" ${image.uuid}" />" x-ext="<c:out value=" ${image.extension}" />" style="cursor: pointer;" class="col-lg-2 col-md-4 col-sm-4 col-xs-6">
<div x-uuid="<c:out value="${image.uuid}" />" x-ext="<c:out value="${image.extension}" />" style="cursor: pointer;" class="col-lg-2 col-md-4 col-sm-4 col-xs-6">
<div class="img-wrapper">
<img src="<c:url value=" /repository/d/_thumbs${image.thumbnailPath}/${thumbnailFormat}.png" />" alt="<c:out value=" ${image.title}" />"/>
<img src="<c:url value="${cdnServers.next}/repository/d/_thumbs${image.thumbnailPath}/${thumbnailFormat}.png" />" alt="<c:out value="${image.title}" />"/>
</div>
</div>
</c:forEach>
......@@ -1076,30 +1076,22 @@
<script type="text/javascript">
jQuery(document).ready(function () {
var map = L.map('map', {scrollWheelZoom: false}).setView([
$ {
accessionGeo.latitude
},
$ {accessionGeo.longitude}
${accessionGeo.latitude}, ${accessionGeo.longitude}
], 4);
L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}', {
attribution: "Tiles &copy; Esri &mdash; Esri, DeLorme, NAVTEQ",
maxZoom: 16
}).addTo(map);
var marker = L.marker([
$ {
accessionGeo.latitude
},
$ {accessionGeo.longitude}
${accessionGeo.latitude}, ${accessionGeo.longitude}
]).addTo(map);
});
</script>
</c:if>
<c:if test="${worldclimJson ne null}">
<script type="text/javascript">
var monthNames = $ {
jspHelper.toJson(jspHelper.monthShortNames(pageContext.response.locale))
};
var worldclim = $ {jspHelper.toJson(worldclimJson)};
var monthNames = ${jspHelper.toJson(jspHelper.monthShortNames(pageContext.response.locale))};
var worldclim = ${jspHelper.toJson(worldclimJson)};
function arrayToData(array) {
var ret = [];
for (var i = 0; i < 12; i++) {
......@@ -1213,11 +1205,12 @@
var elem = box.find('.downloadLink').show().find('a').first().attr('href', box.parent().parent().find('.theimage').first().attr('src'));
}
function showImage(imagegalleryFrame, imageUuid, imageExt) {
var baseHref = '<c:url value="/repository/d" />/';
var baseHref = '<c:url value="/repository/d/" />';
var imageViewer = $(imagegalleryFrame).find('.theimage').first();
var metadataBox = $(imagegalleryFrame).find('.metadata').first();
imageViewer.attr('src', baseHref + imageUuid.substring(0, 3) + '/' + imageUuid + imageExt);
// console.log('Image source: ' + imageViewer.src) console.log(imageViewer.attr('src'));
imageViewer.attr('src', '<c:url value="${cdnServers.next}/repository/d/" />' + imageUuid.substring(0, 3) + '/' + imageUuid + imageExt);
// console.log('Image source: ' + imageViewer.src);
// console.log(imageViewer.attr('src'));
$(imagegalleryFrame).show();
$(metadataBox).hide();
......
......@@ -13,7 +13,7 @@
<html>
<head>
<title><spring:message code="accession.page.data.title"/></title>
<script type="text/javascript" src="<c:url value="/html/1/js/browse.js" />"></script>
<script type="text/javascript" src="<c:url value="${cdnServers.next}/html/1/js/browse.js" />"></script>
<script type="text/javascript" src="<c:url value=</