@SuppressWarnings("rawtypes") @Override protected void readSystemAttributes() throws QuickFixException { super.readSystemAttributes(); builder.setLocalId(getSystemAttributeValue("id")); String load = getSystemAttributeValue("load"); if (!AuraTextUtil.isNullEmptyOrWhitespace(load)) { Load loadVal; try { loadVal = Load.valueOf(load.toUpperCase()); } catch (IllegalArgumentException e) { throw new AuraRuntimeException( String.format("Invalid value '%s' specified for 'aura:load' attribute", load), getLocation()); } builder.setLoad(loadVal); if (loadVal == Load.LAZY || loadVal == Load.EXCLUSIVE) { ((BaseComponentDefHandler) getParentHandler()).setRender("client"); } } String flavor = getSystemAttributeValue("flavor"); if (!AuraTextUtil.isNullEmptyOrWhitespace(flavor)) { builder.setFlavor(flavor); } }
@SuppressWarnings("unchecked") private Map<String, Object> getConfigMap(HttpServletRequest request) { Map<String, Object> configMap = null; String config = contextConfig.get(request); if (!AuraTextUtil.isNullEmptyOrWhitespace(config)) { if (config.startsWith(AuraTextUtil.urlencode("{"))) { // Decode encoded context json. Serialized AuraContext json always starts with "{" config = AuraTextUtil.urldecode(config); } configMap = (Map<String, Object>) new JsonReader().read(config); } return configMap; }
public void assertClassesSame(String message, String expectedClasses, String actualClasses) { List<String> expected = AuraTextUtil.splitSimpleAndTrim(" ", expectedClasses, 3); List<String> actual = AuraTextUtil.splitSimpleAndTrim(" ", actualClasses, 3); List<String> extra = Lists.newArrayList(); for (String x : actual) { if (expected.contains(x)) { expected.remove(x); } else { extra.add(x); } } Assert.assertTrue( message + ": Mismatched classes extra = " + extra + ", missing=" + expected, extra.size() == 0 && expected.size() == 0); }
@Override @SuppressWarnings("unchecked") public IncludeDefImpl getElement() throws XMLStreamException, QuickFixException { if (parentHandler.getDefDescriptor().getDefType() != DefType.LIBRARY) { error("aura:include may only be set in a library."); } DefDescriptor<LibraryDef> parentDescriptor = (DefDescriptor<LibraryDef>) parentHandler.getDefDescriptor(); builder.setLocation(getLocation()); String name = getAttributeValue(ATTRIBUTE_NAME); if (!AuraTextUtil.isNullEmptyOrWhitespace(name)) { builder.setName(name); } else { error("aura:include must specify a valid library name."); } if (name.toLowerCase().endsWith(".js")) { name = name.substring(0, name.length() - 3); } builder.setDescriptor( DefDescriptorImpl.getInstance( String.format("js://%s.%s", parentDescriptor.getNamespace(), name), IncludeDef.class, parentDescriptor)); String imports = getAttributeValue(ATTRIBUTE_IMPORTS); if (!AuraTextUtil.isNullEmptyOrWhitespace(imports)) { builder.setImports(Arrays.asList(imports.split("\\s*\\,\\s*"))); } String exports = getAttributeValue(ATTRIBUTE_EXPORTS); if (!AuraTextUtil.isNullEmptyOrWhitespace(exports)) { builder.setExports(exports); } builder.setParentDescriptor(parentDescriptor); int next = xmlReader.next(); if (next != XMLStreamConstants.END_ELEMENT || !TAG.equalsIgnoreCase(getTagName())) { error("expected end of %s tag", TAG); } builder.setOwnHash(source.getHash()); return builder.build(); }
private void addAttributes(StringBuilder builder, Map<String, Object> attributes) { // // This feels a lot like a hack. // if (attributes != null && !attributes.isEmpty()) { builder.append("?aura.attributes="); builder.append(AuraTextUtil.urlencode(JsonEncoder.serialize(attributes, false, false))); } }
@Override protected void readAttributes() throws InvalidDefinitionException { String componentFilter = getAttributeValue(ATTRIBUTE_COMPONENT); if (!AuraTextUtil.isNullEmptyOrWhitespace(componentFilter)) { builder.setComponent(componentFilter); } else { throw new InvalidDefinitionException("Missing required attribute 'component'", getLocation()); } String flavorFilter = getAttributeValue(ATTRIBUTE_DEFAULT); if (!AuraTextUtil.isNullEmptyOrWhitespace(flavorFilter)) { builder.setFlavor(flavorFilter); } else { throw new InvalidDefinitionException("Missing required attribute 'default'", getLocation()); } builder.setDescription(getAttributeValue(ATTRIBUTE_DESCRIPTION)); builder.setParentDescriptor(getParentDefDescriptor()); builder.setDescriptor(definitionService.getDefDescriptor(flavorFilter, FlavorDefaultDef.class)); }
@Override protected String getAttributeValue(String name) { String value = xmlReader.getAttributeValue(null, name); if (AuraTextUtil.isNullEmptyOrWhitespace(value)) { for (int i = 0; i < xmlReader.getAttributeCount(); i++) { if (xmlReader.getAttributeLocalName(i).equalsIgnoreCase(name)) { return xmlReader.getAttributeValue(i); } } } return value; }
public void testRun() throws Throwable { addMocksToTestContextLocalDef(caseDef.getLocalDefs()); open(getUrl(), Mode.AUTOJSTEST); String ret = (String) auraUITestingUtil.getEval( String.format( "return window.aura.test.run('%s', '%s', 30)", AuraTextUtil.escapeForJavascriptString(caseDef.getName()), AuraTextUtil.escapeForJavascriptString(suite.getCode()))); if (ret != null && !"null".equals(ret)) { @SuppressWarnings("unchecked") Map<String, Object> e = (Map<String, Object>) new JsonReader().read(ret); fail((String) e.get("message")); } // Actions run on servers need special handling because their call // back methods are called asynchronously. // This check is to make sure all such calls were complete waitForCondition("return window.aura.test.isComplete()", 30); }
@Override protected void validateAttributes() { if (!isSystemTag()) { return; } Set<String> allowedAttributes = getAllowedAttributes(); for (int i = 0; i < xmlReader.getAttributeCount(); i++) { QName qname = xmlReader.getAttributeName(i); String localPart = qname.getLocalPart(); String prefix = qname.getPrefix(); if (prefix != null && !prefix.isEmpty() && !prefix.equalsIgnoreCase(SYSTEM_TAG_PREFIX)) { throw new InvalidSystemAttributeException(prefix + ":" + localPart, getLocation()); } else if (!AuraTextUtil.containsIgnoreCase(localPart, allowedAttributes)) { throw new InvalidSystemAttributeException(localPart, getLocation()); } } }
@SuppressWarnings("unchecked") private void verifyStyleDefSerialization(DefDescriptor<StyleDef> styleDesc, Boolean expectCode) throws Exception { String serialized = Json.serialize(styleDesc.getDef()); Object o = new JsonReader().read(serialized); assertTrue(o instanceof Map); Map<String, Object> outerMap = (Map<String, Object>) o; assertEquals(styleDesc.toString(), outerMap.get("descriptor")); assertEquals( styleDesc.getNamespace() + AuraTextUtil.initCap(styleDesc.getName()), outerMap.get("className")); if (expectCode) { assertEquals( "StyleDef content not included.", styleDesc.getDef().getCode(), outerMap.get("code")); } else { assertNull("StyleDef content should not be included.", outerMap.get("code")); } }
@Override protected void fix() throws Exception { String descriptor = (String) getAttributes().get("descriptor"); String name = (String) getAttributes().get("name"); String defaultValue = (String) getAttributes().get("defaultValue"); DefDescriptor<?> desc = Aura.getDefinitionService().getDefDescriptor(descriptor, ThemeDef.class); Source<?> source = Aura.getContextService().getCurrentContext().getDefRegistry().getSource(desc); if ("".equals(name)) { throw new AuraRuntimeException("Cannot leave the name field blank"); } if ((AuraTextUtil.validateAttributeName(name)) != true) { throw new AuraRuntimeException( "Invalid var name:'" + name + "', Refer to Auradocs for valid attribute names"); } if (!source.exists()) { throw new AuraError("Cannot find source for " + desc.getQualifiedName()); } String s = source.getContents(); Matcher m = TAG.matcher(s); if (m.find()) { StringBuilder sb = new StringBuilder(s.length() + 50); sb.append(s.subSequence(0, m.end())); sb.append("\n <aura:var name=\""); sb.append(name); sb.append("\" value=\""); sb.append(defaultValue); sb.append("\"/>\n"); sb.append(s.substring(m.end() + 1)); Writer writer = source.getWriter(); try { writer.write(sb.toString()); } finally { writer.close(); } } else { throw new AuraError("Could not locate opening tag for " + desc.getQualifiedName()); } }
public DefOverviewModel() throws QuickFixException { AuraContext context = Aura.getContextService().getCurrentContext(); BaseComponent<?, ?> component = context.getCurrentComponent(); String desc = (String) component.getAttributes().getValue("descriptor"); DefType defType = DefType.valueOf(((String) component.getAttributes().getValue("defType")).toUpperCase()); DefinitionService definitionService = Aura.getDefinitionService(); DefDescriptor<?> descriptor = definitionService.getDefDescriptor(desc, defType.getPrimaryInterface()); Definition def = descriptor.getDef(); ReferenceTreeModel.assertAccess(def); Map<DefType, List<DefModel>> depsMap = Maps.newEnumMap(DefType.class); Set<DefDescriptor<?>> deps = Sets.newHashSet(); def.appendDependencies(deps); for (DefDescriptor<?> dep : deps) { DefType type = dep.getDefType(); List<DefModel> depsList = depsMap.get(type); if (depsList == null) { depsList = Lists.newArrayList(); depsMap.put(type, depsList); } depsList.add(new DefModel(dep)); } for (Entry<DefType, List<DefModel>> entry : depsMap.entrySet()) { List<DefModel> list = entry.getValue(); Collections.sort(list); Map<String, Object> group = Maps.newHashMap(); group.put("type", AuraTextUtil.initCap(entry.getKey().toString().toLowerCase())); group.put("list", list); dependencies.add(group); } }
/** * Check a manifest cookie and update. * * <p>This routine will check and update a manifest cookie value to ensure that we are not * looping. If the incoming cookie is null, it simply initializes, othewise, it parses the cookie * and returns null if it requires a reset. * * @param incoming the cookie from the client. * @return either an updated cookie, or null if it was invalid. */ public static String updateManifestCookieValue(String incoming) { int manifestRequestCount = 0; long now = System.currentTimeMillis(); long cookieTime = now; if (MANIFEST_ERROR.equals(incoming)) { return null; } else { List<String> parts = AuraTextUtil.splitSimple(":", incoming, 2); if (parts != null && parts.size() == 2) { String count = parts.get(0); String date = parts.get(1); try { manifestRequestCount = Integer.parseInt(count); cookieTime = Long.parseLong(date); if (now - cookieTime > MAX_MANIFEST_TIME) { // // If we have gone off by more than 60 seconds, // reset everything to start the counter. // manifestRequestCount = 0; cookieTime = now; } if (manifestRequestCount >= MAX_MANIFEST_COUNT) { // We have had 5 requests in 60 seconds. bolt. return null; } } catch (NumberFormatException e) { // // Bad cookie! // This should actually be very hard to have happen, // since it requires a cookie to have a ':' in it, // and also to have unparseable numbers, so just punt // return null; } } } manifestRequestCount += 1; return manifestRequestCount + ":" + cookieTime; }
/** * get the manifest URL. * * <p>This routine will simply return the string, it does not check to see if the manifest is * enabled first. * * @return a string for the manifest URL. */ public static String getManifestUrl() throws QuickFixException { AuraContext context = Aura.getContextService().getCurrentContext(); String contextPath = context.getContextPath(); String ret = ""; boolean serLastMod = context.getSerializeLastMod(); StringBuilder defs = new StringBuilder(contextPath).append("/l/"); StringBuilder sb = new StringBuilder(); context.setSerializeLastMod(false); try { Aura.getSerializationService().write(context, null, AuraContext.class, sb, "HTML"); } catch (IOException e) { throw new AuraRuntimeException(e); } context.setSerializeLastMod(serLastMod); String contextJson = AuraTextUtil.urlencode(sb.toString()); defs.append(contextJson); defs.append("/app.manifest"); ret = defs.toString(); return ret; }
/** * Gets system attribute by prepending system prefix. * * @param name attribute name * @return attribute value */ protected String getSystemAttributeValue(String name) { // W-2316503: remove compatibility code for both SJSXP and Woodstox String value = getAttributeValue(SYSTEM_TAG_PREFIX + ":" + name); if (value != null) { // woodstox // With IS_NAMESPACE_AWARE disabled, woodstox will not set attribute prefix // so we can get the value from entire attribute name return value; } else { // sjsxp // defaults to setting attribute prefix regardless of IS_NAMESPACE_AWARE setting value = getAttributeValue(name); if (!AuraTextUtil.isNullEmptyOrWhitespace(value)) { // ensure system prefixed value of attribute ie "id" vs "aura:id" for (int i = 0; i < xmlReader.getAttributeCount(); i++) { if (xmlReader.getAttributeLocalName(i).equalsIgnoreCase(name) && SYSTEM_TAG_PREFIX.equalsIgnoreCase(xmlReader.getAttributePrefix(i))) { return xmlReader.getAttributeValue(i); } } } return null; } }
protected Map<DefDescriptor<AttributeDef>, AttributeDefRef> getAttributes() throws QuickFixException { // TODOJT: add varargs "validAttributeNames" to this and validate that // any attributes we find are in that list. // TODOJT: possibly those arguments are like *Param objects with // built-in value validation? Map<DefDescriptor<AttributeDef>, AttributeDefRef> attributes = new LinkedHashMap<>(); for (int i = 0; i < xmlReader.getAttributeCount(); i++) { String attName = xmlReader.getAttributeLocalName(i); String prefix = xmlReader.getAttributePrefix(i); if (!XMLHandler.isSystemPrefixed(attName, prefix)) { // W-2316503: remove compatibility code for both SJSXP and Woodstox if (!AuraTextUtil.isNullEmptyOrWhitespace(prefix) && !attName.contains(":")) { attName = prefix + ":" + attName; } DefDescriptor<AttributeDef> att = DefDescriptorImpl.getInstance(attName, AttributeDef.class); String attValue = xmlReader.getAttributeValue(i); if (attributes.containsKey(att)) { error("Duplicate values for attribute %s on tag %s", att, getTagName()); } TextTokenizer tt = TextTokenizer.tokenize(attValue, getLocation()); Object value = tt.asValue(getParentHandler()); AttributeDefRefImpl.Builder atBuilder = new AttributeDefRefImpl.Builder(); atBuilder.setDescriptor(att); atBuilder.setLocation(getLocation()); atBuilder.setValue(value); attributes.put(att, atBuilder.build()); } } return attributes; }
/** * Handle an exception in the servlet. * * <p>This routine should be called whenever an exception has surfaced to the top level of the * servlet. It should not be overridden unless Aura is entirely subsumed. Most special cases can * be handled by the Aura user by implementing {@link ExceptionAdapter ExceptionAdapter}. * * @param t the throwable to write out. * @param quickfix is this exception a valid quick-fix * @param context the aura context. * @param request the request. * @param response the response. * @param written true if we have started writing to the output stream. * @throws IOException if the output stream does. * @throws ServletException if send404 does (should not generally happen). */ @Override public void handleServletException( Throwable t, boolean quickfix, AuraContext context, HttpServletRequest request, HttpServletResponse response, boolean written) throws IOException { try { Throwable mappedEx = t; boolean map = !quickfix; Format format = context.getFormat(); // // This seems to fail, though the documentation implies that you can do // it. // // if (written && !response.isCommitted()) { // response.resetBuffer(); // written = false; // } if (!written) { // Should we only delete for JSON? setNoCache(response); } if (mappedEx instanceof IOException) { // // Just re-throw IOExceptions. // throw (IOException) mappedEx; } else if (mappedEx instanceof NoAccessException) { Throwable cause = mappedEx.getCause(); String denyMessage = mappedEx.getMessage(); map = false; if (cause != null) { // // Note that the exception handler can remap the cause here. // cause = exceptionAdapter.handleException(cause); denyMessage += ": cause = " + cause.getMessage(); } // // Is this correct?!?!?! // if (format != Format.JSON) { this.send404(request.getServletContext(), request, response); if (!isProductionMode(context.getMode())) { // Preserve new lines and tabs in the stacktrace since this is directly being written on // to the // page denyMessage = "<pre>" + AuraTextUtil.escapeForHTML(denyMessage) + "</pre>"; response.getWriter().println(denyMessage); } return; } } else if (mappedEx instanceof QuickFixException) { if (isProductionMode(context.getMode())) { // // In production environments, we want wrap the quick-fix. But be a little careful here. // We should never mark the top level as a quick-fix, because that means that we gack // on every mis-spelled app. In this case we simply send a 404 and bolt. // if (mappedEx instanceof DefinitionNotFoundException) { DefinitionNotFoundException dnfe = (DefinitionNotFoundException) mappedEx; if (dnfe.getDescriptor() != null && dnfe.getDescriptor().equals(context.getApplicationDescriptor())) { // We're in production and tried to hit an aura app that doesn't exist. // just show the standard 404 page. this.send404(request.getServletContext(), request, response); return; } } map = true; mappedEx = new AuraUnhandledException("404 Not Found (Application Error)", mappedEx); } } if (map) { mappedEx = exceptionAdapter.handleException(mappedEx); } PrintWriter out = response.getWriter(); // // If we have written out data, We are kinda toast in this case. // We really want to roll it all back, but we can't, so we opt // for the best we can do. For HTML we can do nothing at all. // if (format == Format.JSON) { if (!written) { out.write(CSRF_PROTECT); } // // If an exception happened while we were emitting JSON, we want the // client to ignore the now-corrupt data structure. 404s and 500s // cause the client to prepend /*, so we can effectively erase the // bad data by appending a */ here and then serializing the exception // info. // out.write("*/"); // // Unfortunately we can't do the following now. It might be possible // in some cases, but we don't want to go there unless we have to. // } if (format == Format.JS || format == Format.CSS) { // Make sure js and css doesn't get cached in browser, appcache, etc response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); } if (format == Format.JSON || format == Format.HTML || format == Format.JS || format == Format.CSS) { // // We only write out exceptions for HTML or JSON. // Seems bogus, but here it is. // // Start out by cleaning out some settings to ensure we don't // check too many things, leading to a circular failure. Note // that this is still a bit dangerous, as we seem to have a lot // of magic in the serializer. // // Clear the InstanceStack before trying to serialize the exception since the Throwable has // likely // rendered the stack inaccurate, and may falsely trigger NoAccessExceptions. InstanceStack stack = this.contextService.getCurrentContext().getInstanceStack(); List<String> list = stack.getStackInfo(); for (int count = list.size(); count > 0; count--) { stack.popInstance(stack.peek()); } serializationService.write(mappedEx, null, out); if (format == Format.JSON) { out.write("/*ERROR*/"); } } } catch (IOException ioe) { throw ioe; } catch (Throwable death) { // // Catch any other exception and log it. This is actually kinda bad, because something has // gone horribly wrong. We should write out some sort of generic page other than a 404, // but at this point, it is unclear what we can do, as stuff is breaking right and left. // try { response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); exceptionAdapter.handleException(death); if (!isProductionMode(context.getMode())) { response.getWriter().println(death.getMessage()); } } catch (IOException ioe) { throw ioe; } catch (Throwable doubleDeath) { // we are totally hosed. if (!isProductionMode(context.getMode())) { response.getWriter().println(doubleDeath.getMessage()); } } } finally { this.contextService.endContext(); } }
@Override protected void handleChildText() throws XMLStreamException, QuickFixException { if (!AuraTextUtil.isNullEmptyOrWhitespace(xmlReader.getText())) { error("No literal text allowed in %s tag", TAG); } }
@Override @SuppressWarnings("unchecked") public IncludeDefRefImpl getElement() throws XMLStreamException, QuickFixException { DefDescriptor<LibraryDef> parentDescriptor = (DefDescriptor<LibraryDef>) parentHandler.getDefDescriptor(); if (parentDescriptor.getDefType() != DefType.LIBRARY) { throw new InvalidDefinitionException( "aura:include may only be set in a library.", getLocation()); } validateAttributes(); builder.setLocation(getLocation()); String name = getAttributeValue(ATTRIBUTE_NAME); if (AuraTextUtil.isNullEmptyOrWhitespace(name)) { throw new InvalidDefinitionException( ("aura:include must specify a valid library name."), getLocation()); } builder.setDescriptor( SubDefDescriptorImpl.getInstance(name, parentDescriptor, IncludeDefRef.class)); builder.setIncludeDescriptor( DefDescriptorImpl.getInstance( String.format("%s.%s", parentDescriptor.getNamespace(), name), IncludeDef.class, parentDescriptor)); String importNames = getAttributeValue(ATTRIBUTE_IMPORTS); if (!AuraTextUtil.isNullEmptyOrWhitespace(importNames)) { List<DefDescriptor<IncludeDef>> imports = Lists.newLinkedList(); for (String importName : Arrays.asList(importNames.trim().split("\\s*\\,\\s*"))) { String[] parts = importName.split(":"); if (parts.length == 1) { // local import imports.add( DefDescriptorImpl.getInstance( String.format("%s.%s", parentDescriptor.getNamespace(), importName), IncludeDef.class, parentDescriptor)); } else if (parts.length == 3) { // external import DefDescriptor<LibraryDef> externalLibrary = DefDescriptorImpl.getInstance( String.format("%s:%s", parts[0], parts[1]), LibraryDef.class); imports.add( DefDescriptorImpl.getInstance( String.format("%s.%s", parts[0], parts[2]), IncludeDef.class, externalLibrary)); } else { // invalid import name throw new InvalidDefinitionException( String.format("Invalid name in aura:include imports property: %s", importName), getLocation()); } } builder.setImports(imports); } String export = getAttributeValue(ATTRIBUTE_EXPORT); if (!AuraTextUtil.isNullEmptyOrWhitespace(export)) { builder.setExport(export); } builder.setDescription(getAttributeValue(RootTagHandler.ATTRIBUTE_DESCRIPTION)); int next = xmlReader.next(); if (next != XMLStreamConstants.END_ELEMENT || !TAG.equalsIgnoreCase(getTagName())) { error("expected end of %s tag", TAG); } builder.setOwnHash(source.getHash()); return builder.build(); }
public void testGetClassName() throws QuickFixException { DefDescriptor<StyleDef> style = addStyleDef(".THIS {color: red }"); String expected = style.getNamespace() + AuraTextUtil.initCap(style.getName()); assertEquals(expected, style.getDef().getClassName()); }