@SetupRender final void setup() { // Often, these controlName and clientId will end up as the same value. There are many // exceptions, including a form that renders inside a loop, or a form inside a component // that is used multiple times. if (formSupport == null) throw new RuntimeException( String.format( "Component %s must be enclosed by a Form component.", resources.getCompleteId())); assignedClientId = allocateClientId(); String controlName = formSupport.allocateControlName(resources.getId()); formSupport.storeAndExecute(this, new Setup(controlName)); formSupport.store(this, PROCESS_SUBMISSION_ACTION); }
public Asset getComponentAsset( final ComponentResources resources, final String path, final String libraryName) { assert resources != null; assert InternalUtils.isNonBlank(path); return tracker.invoke( String.format("Resolving '%s' for component %s", path, resources.getCompleteId()), new Invokable<Asset>() { public Asset invoke() { // First, expand symbols: String expanded = symbolSource.expandSymbols(path); int dotx = expanded.indexOf(':'); // We special case the hell out of 'classpath:' so that we can provide warnings today // (5.4) and // blow up in a useful fashion tomorrow (5.5). if (expanded.startsWith("//") || (dotx > 0 && !expanded.substring(0, dotx).equalsIgnoreCase(AssetConstants.CLASSPATH))) { final String prefix = dotx >= 0 ? expanded.substring(0, dotx) : AssetConstants.PROTOCOL_RELATIVE; if (EXTERNAL_URL_PREFIXES.contains(prefix)) { String url; if (prefix.equals(AssetConstants.PROTOCOL_RELATIVE)) { url = (request != null && request.isSecure() ? "https:" : "http:") + expanded; url = url.replace("//:", "//"); } else { url = expanded; } try { UrlResource resource = new UrlResource(new URL(url)); return new UrlAsset(url, resource); } catch (MalformedURLException e) { throw new RuntimeException(e); } } else { return getAssetInLocale( resources.getBaseResource(), expanded, resources.getLocale()); } } // No prefix, so implicitly classpath:, or explicitly classpath: String restOfPath = expanded.substring(dotx + 1); // This is tricky, because a relative path (including "../") is ok in 5.3, since its // just somewhere // else on the classpath (though you can "stray" out of the "safe" zone). In 5.4, under // /META-INF/assets/ // it's possible to "stray" out beyond the safe zone more easily, into parts of the // classpath that can't be // represented in the URL. // Ends with trailing slash: String metaRoot = "META-INF/assets/" + toPathPrefix(libraryName); String trimmedRestOfPath = restOfPath.startsWith("/") ? restOfPath.substring(1) : restOfPath; // TAP5-2044: Some components specify a full path, starting with META-INF/assets/, and // we should just trust them. // The warning logic below is for compnents that specify a relative path. Our bad // decisions come back to haunt us; // Resource paths should always had a leading slash to differentiate relative from // complete. String metaPath = trimmedRestOfPath.startsWith("META-INF/assets/") ? trimmedRestOfPath : metaRoot + trimmedRestOfPath; // Based on the path, metaResource is where it should exist in a 5.4 and beyond world // ... unless the expanded // path was a bit too full of ../ sequences, in which case the expanded path is not // valid and we adjust the // error we write. Resource metaResource = findLocalizedResource(null, metaPath, resources.getLocale()); Asset result = getComponentAsset(resources, expanded, metaResource); if (result == null) { throw new RuntimeException( String.format( "Unable to locate asset '%s' for component %s. It should be located at %s.", path, resources.getCompleteId(), metaPath)); } // This is the best way to tell if the result is an asset for a Classpath resource. Resource resultResource = result.getResource(); if (!resultResource.equals(metaResource)) { if (firstWarning.getAndSet(false)) { logger.error( "Packaging of classpath assets has changed in release 5.4; " + "Assets should no longer be on the main classpath, " + "but should be moved to 'META-INF/assets/' or a sub-folder. Future releases of Tapestry may " + "no longer support assets on the main classpath."); } if (metaResource.getFolder().startsWith(metaRoot)) { logger.warn( String.format( "Classpath asset '/%s' should be moved to folder '/%s/'.", resultResource.getPath(), metaResource.getFolder())); } else { logger.warn( String.format( "Classpath asset '/%s' should be moved under folder '/%s', and the relative path adjusted.", resultResource.getPath(), metaRoot)); } } return result; } }); }