├── .gitignore ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── Procfile ├── README.md ├── SECURITY.md ├── app.json ├── pom.xml ├── src └── main │ ├── java │ ├── Main.java │ ├── canvas │ │ ├── CanvasApplicationContext.java │ │ ├── CanvasClient.java │ │ ├── CanvasContext.java │ │ ├── CanvasEnvironmentContext.java │ │ ├── CanvasLinkContext.java │ │ ├── CanvasOrganizationContext.java │ │ ├── CanvasRequest.java │ │ ├── CanvasUserContext.java │ │ └── SignedRequest.java │ ├── servlets │ │ ├── AbstractServlet.java │ │ ├── CallbackController.java │ │ ├── CanvasController.java │ │ ├── OAuthServlet.java │ │ └── ProxyServlet.java │ └── util │ │ ├── Browser.java │ │ ├── Device.java │ │ └── UserAgent.java │ └── webapp │ ├── ChatterFeed │ ├── chatterfeed-mobile.css │ ├── chatterfeed.css │ └── index.jsp │ ├── MobileNav │ ├── index.jsp │ └── mobile-nav.css │ ├── Publisher │ ├── index.jsp │ ├── publisher-desktop.css │ ├── publisher-mobile.css │ ├── publisher.css │ └── publisher.js │ ├── WEB-INF │ └── web.xml │ ├── canvas.jsp │ ├── default │ ├── api.jsp │ ├── context.jsp │ ├── default-mobile.css │ ├── default.css │ ├── events.jsp │ ├── index.jsp │ ├── resize.jsp │ ├── scroll.jsp │ ├── tabs-mobile.css │ ├── tabs.css │ └── tabs.js │ ├── icon.png │ ├── images │ ├── canvaslogo.png │ ├── salesforce.png │ └── share.png │ ├── index.html │ ├── logo.png │ ├── scripts │ ├── chatter-talk.js │ └── json2.js │ ├── sdk │ ├── callback.html │ ├── css │ │ └── canvas.css │ └── js │ │ └── canvas-all.js │ ├── signed-request.jsp │ ├── user-approval.jsp │ └── welcome.jsp └── system.properties /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.iws 3 | *.ipr 4 | *.class 5 | .project 6 | .classpath 7 | keystore 8 | target/ 9 | .settings/ 10 | .DS_Store 11 | 12 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Comment line immediately above ownership line is reserved for related gus information. Please be careful while editing. 2 | #ECCN:Open Source 3 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Salesforce Open Source Community Code of Conduct 2 | 3 | ## About the Code of Conduct 4 | 5 | Equality is a core value at Salesforce. We believe a diverse and inclusive 6 | community fosters innovation and creativity, and are committed to building a 7 | culture where everyone feels included. 8 | 9 | Salesforce open-source projects are committed to providing a friendly, safe, and 10 | welcoming environment for all, regardless of gender identity and expression, 11 | sexual orientation, disability, physical appearance, body size, ethnicity, nationality, 12 | race, age, religion, level of experience, education, socioeconomic status, or 13 | other similar personal characteristics. 14 | 15 | The goal of this code of conduct is to specify a baseline standard of behavior so 16 | that people with different social values and communication styles can work 17 | together effectively, productively, and respectfully in our open source community. 18 | It also establishes a mechanism for reporting issues and resolving conflicts. 19 | 20 | All questions and reports of abusive, harassing, or otherwise unacceptable behavior 21 | in a Salesforce open-source project may be reported by contacting the Salesforce 22 | Open Source Conduct Committee at ossconduct@salesforce.com. 23 | 24 | ## Our Pledge 25 | 26 | In the interest of fostering an open and welcoming environment, we as 27 | contributors and maintainers pledge to making participation in our project and 28 | our community a harassment-free experience for everyone, regardless of gender 29 | identity and expression, sexual orientation, disability, physical appearance, 30 | body size, ethnicity, nationality, race, age, religion, level of experience, education, 31 | socioeconomic status, or other similar personal characteristics. 32 | 33 | ## Our Standards 34 | 35 | Examples of behavior that contributes to creating a positive environment 36 | include: 37 | 38 | * Using welcoming and inclusive language 39 | * Being respectful of differing viewpoints and experiences 40 | * Gracefully accepting constructive criticism 41 | * Focusing on what is best for the community 42 | * Showing empathy toward other community members 43 | 44 | Examples of unacceptable behavior by participants include: 45 | 46 | * The use of sexualized language or imagery and unwelcome sexual attention or 47 | advances 48 | * Personal attacks, insulting/derogatory comments, or trolling 49 | * Public or private harassment 50 | * Publishing, or threatening to publish, others' private information—such as 51 | a physical or electronic address—without explicit permission 52 | * Other conduct which could reasonably be considered inappropriate in a 53 | professional setting 54 | * Advocating for or encouraging any of the above behaviors 55 | 56 | ## Our Responsibilities 57 | 58 | Project maintainers are responsible for clarifying the standards of acceptable 59 | behavior and are expected to take appropriate and fair corrective action in 60 | response to any instances of unacceptable behavior. 61 | 62 | Project maintainers have the right and responsibility to remove, edit, or 63 | reject comments, commits, code, wiki edits, issues, and other contributions 64 | that are not aligned with this Code of Conduct, or to ban temporarily or 65 | permanently any contributor for other behaviors that they deem inappropriate, 66 | threatening, offensive, or harmful. 67 | 68 | ## Scope 69 | 70 | This Code of Conduct applies both within project spaces and in public spaces 71 | when an individual is representing the project or its community. Examples of 72 | representing a project or community include using an official project email 73 | address, posting via an official social media account, or acting as an appointed 74 | representative at an online or offline event. Representation of a project may be 75 | further defined and clarified by project maintainers. 76 | 77 | ## Enforcement 78 | 79 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 80 | reported by contacting the Salesforce Open Source Conduct Committee 81 | at ossconduct@salesforce.com. All complaints will be reviewed and investigated 82 | and will result in a response that is deemed necessary and appropriate to the 83 | circumstances. The committee is obligated to maintain confidentiality with 84 | regard to the reporter of an incident. Further details of specific enforcement 85 | policies may be posted separately. 86 | 87 | Project maintainers who do not follow or enforce the Code of Conduct in good 88 | faith may face temporary or permanent repercussions as determined by other 89 | members of the project's leadership and the Salesforce Open Source Conduct 90 | Committee. 91 | 92 | ## Attribution 93 | 94 | This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant-home], 95 | version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html. 96 | It includes adaptions and additions from [Go Community Code of Conduct][golang-coc], 97 | [CNCF Code of Conduct][cncf-coc], and [Microsoft Open Source Code of Conduct][microsoft-coc]. 98 | 99 | This Code of Conduct is licensed under the [Creative Commons Attribution 3.0 License][cc-by-3-us]. 100 | 101 | [contributor-covenant-home]: https://www.contributor-covenant.org (https://www.contributor-covenant.org/) 102 | [golang-coc]: https://golang.org/conduct 103 | [cncf-coc]: https://github.com/cncf/foundation/blob/master/code-of-conduct.md 104 | [microsoft-coc]: https://opensource.microsoft.com/codeofconduct/ 105 | [cc-by-3-us]: https://creativecommons.org/licenses/by/3.0/us/ 106 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Copyright (c) 2012, Salesforce.com, Inc. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: sh target/bin/webapp 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SFDC Canvas Java Template 2 | ============================ 3 | 4 | Salesforce Canvas is a mashup framework for consuming third party applications within Salesforce. Its goal is to connect applications at a UI level instead of an API level. Platform Connect will provide third party applications with a JavaScript SDK along with Java classes so they can seamlessly integrate canvas style applications, while developing in the technology and platform of their choice. 5 | 6 | ### How to Build The app locally 7 | 8 | mvn package 9 | 10 | ### First time keystore generation (for local SSL support) 11 | 12 | > keytool -keystore keystore -alias jetty -genkey -keyalg RSA 13 | Enter keystore password: 123456 14 | Re-enter new password: 123456 15 | What is your first and last name? 16 | [Unknown]: 17 | What is the name of your organizational unit? 18 | [Unknown]: 19 | What is the name of your organization? 20 | [Unknown]: 21 | What is the name of your City or Locality? 22 | [Unknown]: 23 | What is the name of your State or Province? 24 | [Unknown]: 25 | What is the two-letter country code for this unit? 26 | [Unknown]: 27 | Is CN=, OU=, O=, L=, ST=, C=? 28 | [no]: yes 29 | 30 | Enter key password for 31 | (RETURN if same as keystore password): 32 | Re-enter new password: 33 | 34 | ### How to Run Canvas locally 35 | 36 | sh target/bin/webapp 37 | 38 | ### How to invoke app locally 39 | 40 | https://localhost:8443 41 | 42 | ### Canvas URL 43 | 44 | https://localhost:8443/canvas.jsp 45 | or on Heroku 46 | https://.herokuapp.com/canvas.jsp 47 | 48 | ### Canvas Callback URLs 49 | 50 | https://localhost:8443/sdk/callback.html 51 | or on Heroku 52 | https://.herokuapp.com/sdk/callback.html 53 | 54 | ### How to push new changes to heroku 55 | 56 | git add -A 57 | git commit -m "My change comments" 58 | git push heroku master 59 | 60 | ### How to get Heroku logs 61 | 62 | heroku logs --tail 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security 2 | 3 | Please report any security issue to [security@salesforce.com](mailto:security@salesforce.com) 4 | as soon as it is discovered. This library limits its runtime dependencies in 5 | order to reduce the total cost of ownership as much as can be, but all consumers 6 | should remain vigilant and have their security stakeholders review all third-party 7 | products (3PP) like this one and their dependencies. 8 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Canvas Quickstart Java Template", 3 | "description": "Salesforce Canvas is a mashup framework for consuming third party applications within Salesforce. Its goal is to connect applications at a UI level instead of an API level. Platform Connect will provide third party applications with a JavaScript SDK along with Java classes so they can seamlessly integrate canvas style applications, while developing in the technology and platform of their choice.", 4 | "website": "http://developer.salesforce.com", 5 | "addons": [], 6 | "success_url": "/", 7 | "env": { 8 | "CANVAS_CONSUMER_KEY": { 9 | "description": "The consumer key for connecting to Canvas.", 10 | "value": "Inital Consumer Key Value" 11 | }, 12 | "CANVAS_CONSUMER_SECRET": { 13 | "description": "The consumer secret that signs the Canvas contextual information.", 14 | "value": "Inital Consumer Secret Value" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | sfdc 7 | 1.0-SNAPSHOT 8 | Salesforce Canvas Java Template 9 | sfdc-canvas-java-template 10 | 11 | 12 | 1.8 13 | UTF-8 14 | 9.0.90 15 | 16 | 17 | 18 | 19 | 20 | 21 | jstl 22 | jstl 23 | 1.2 24 | 25 | 26 | org.apache.tomcat.embed 27 | tomcat-embed-core 28 | ${tomcat.version} 29 | 30 | 31 | org.apache.tomcat.embed 32 | tomcat-embed-jasper 33 | ${tomcat.version} 34 | 35 | 36 | org.apache.tomcat 37 | tomcat-jasper 38 | ${tomcat.version} 39 | 40 | 41 | org.apache.tomcat 42 | tomcat-jasper-el 43 | ${tomcat.version} 44 | 45 | 46 | org.apache.tomcat 47 | tomcat-jsp-api 48 | ${tomcat.version} 49 | 50 | 51 | 52 | org.codehaus.jackson 53 | jackson-mapper-asl 54 | 1.9.13 55 | 56 | 57 | 58 | asm 59 | asm 60 | 3.2 61 | 62 | 63 | 64 | 65 | org.json 66 | json 67 | 20080701 68 | 69 | 70 | 71 | 72 | commons-httpclient 73 | commons-httpclient 74 | 3.1 75 | 76 | 77 | commons-codec 78 | commons-codec 79 | 80 | 81 | 82 | 83 | 84 | 85 | commons-codec 86 | commons-codec 87 | 1.4 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | org.apache.maven.plugins 97 | maven-compiler-plugin 98 | 2.3.2 99 | 100 | ${java.version} 101 | ${java.version} 102 | 103 | 104 | 105 | 106 | org.codehaus.mojo 107 | appassembler-maven-plugin 108 | 1.1.1 109 | 110 | target 111 | 112 | 113 | Main 114 | webapp 115 | 116 | 117 | 118 | 119 | 120 | execution1 121 | package 122 | 123 | assemble 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | import java.io.File; 28 | 29 | import org.apache.catalina.WebResourceRoot; 30 | import org.apache.catalina.core.StandardContext; 31 | import org.apache.catalina.startup.Tomcat; 32 | import org.apache.catalina.webresources.DirResourceSet; 33 | import org.apache.catalina.webresources.StandardRoot; 34 | import org.apache.catalina.connector.Connector; 35 | import org.apache.coyote.http11.AbstractHttp11Protocol; 36 | import org.apache.catalina.Context; 37 | import org.apache.tomcat.util.scan.StandardJarScanner; 38 | /** 39 | * 40 | * This class launches the web application in an embedded Jetty container. 41 | * This is the entry point to your application. The Java command that is used for 42 | * launching should fire this main method. 43 | * 44 | * @author John Simone 45 | */ 46 | public class Main { 47 | 48 | /** 49 | * @param args 50 | */ 51 | public static void main(String[] args) throws Exception{ 52 | 53 | boolean heroku = false; 54 | // A hacky way to determine if we are running on heroku or not 55 | String basedir = (String)System.getProperty("basedir"); 56 | if (basedir != null && basedir.endsWith("/app/target")) { 57 | heroku = true; 58 | } 59 | 60 | if (!heroku) { 61 | System.out.println("Looks like we are NOT running on Heroku."); 62 | 63 | String webappDirLocation = "src/main/webapp/"; 64 | 65 | String webPort = System.getenv("PORT"); 66 | if (webPort == null || webPort.isEmpty()) { 67 | webPort = "8080"; 68 | } 69 | 70 | String sslPort = System.getenv("SSLPORT"); 71 | if (sslPort == null || sslPort.isEmpty()) { 72 | sslPort = System.getenv("SSL_PORT"); 73 | if (sslPort == null || sslPort.isEmpty()) { 74 | sslPort = "8443"; 75 | } 76 | } 77 | 78 | Tomcat tomcat = new Tomcat(); 79 | tomcat.setPort(Integer.parseInt(webPort)); 80 | 81 | // HTTP Connector 82 | Connector httpConnector = new Connector("HTTP/1.1"); 83 | httpConnector.setPort(Integer.parseInt(webPort)); 84 | tomcat.getService().addConnector(httpConnector); 85 | 86 | // HTTPS Connector 87 | Connector httpsConnector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); 88 | httpsConnector.setPort(Integer.parseInt(sslPort)); 89 | httpsConnector.setSecure(true); 90 | httpsConnector.setScheme("https"); 91 | httpsConnector.setAttribute("keyAlias", "jetty"); 92 | httpsConnector.setAttribute("keystorePass", "123456"); 93 | httpsConnector.setAttribute("keystoreFile", "keystore"); 94 | httpsConnector.setAttribute("clientAuth", "false"); 95 | httpsConnector.setAttribute("sslProtocol", "TLS"); 96 | httpsConnector.setAttribute("SSLEnabled", true); 97 | tomcat.getService().addConnector(httpsConnector); 98 | 99 | // Set the default connector to HTTP 100 | tomcat.setConnector(httpConnector); 101 | 102 | // Add the web application context 103 | StandardContext ctx = (StandardContext) tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath()); 104 | System.out.println("configuring app with basedir: " + new File("./" + webappDirLocation).getAbsolutePath()); 105 | 106 | File additionWebInfClasses = new File("target/classes"); 107 | WebResourceRoot resources = new StandardRoot(ctx); 108 | resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes", 109 | additionWebInfClasses.getAbsolutePath(), "/")); 110 | ctx.setResources(resources); 111 | 112 | 113 | tomcat.start(); 114 | tomcat.getServer().await(); 115 | } 116 | else { 117 | 118 | // Heroku does it's own SSL piggyback thing 119 | System.out.println("Looks like we are running on heroku."); 120 | 121 | String webappDirLocation = "src/main/webapp/"; 122 | 123 | //The port that we should run on can be set into an environment variable 124 | //Look for that variable and default to 8080 if it isn't there. 125 | String webPort = System.getenv("PORT"); 126 | if(webPort == null || webPort.isEmpty()) { 127 | webPort = "8080"; 128 | } 129 | 130 | Tomcat tomcat = new Tomcat(); 131 | tomcat.setPort(Integer.valueOf(webPort)); 132 | 133 | Connector conn = new Connector(); 134 | conn.setPort(Integer.valueOf(webPort)); 135 | tomcat.setConnector(conn); 136 | 137 | StandardContext ctx = (StandardContext) tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath()); 138 | System.out.println("configuring app with basedir: " + new File("./" + webappDirLocation).getAbsolutePath()); 139 | 140 | File additionWebInfClasses = new File("target/classes"); 141 | WebResourceRoot resources = new StandardRoot(ctx); 142 | resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes", 143 | additionWebInfClasses.getAbsolutePath(), "/")); 144 | ctx.setResources(resources); 145 | 146 | tomcat.start(); 147 | tomcat.getServer().await(); 148 | } 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/canvas/CanvasApplicationContext.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011-2013, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package canvas; 27 | 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | /** 32 | * Describes meta-data about the canvas connected app 33 | */ 34 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 35 | public class CanvasApplicationContext { 36 | 37 | private String namespace; 38 | private String developerName; 39 | private String name; 40 | private String canvasUrl; 41 | private String applicationId; 42 | private String version; 43 | private String authType; 44 | private String referenceId; 45 | private List options; 46 | private String samlInitiationMethod; 47 | 48 | /** 49 | * Developer org's unique namespace. Can be null. 50 | * @return namespace 51 | */ 52 | @org.codehaus.jackson.annotate.JsonProperty("namespace") 53 | public String getNamespace() { 54 | return namespace; 55 | } 56 | 57 | @org.codehaus.jackson.annotate.JsonProperty("namespace") 58 | public void setNamespace(String namespace) { 59 | this.namespace = namespace; 60 | } 61 | 62 | /** 63 | * Developer name of the app. Note this is not the same as the application name. 64 | * @return developerName 65 | */ 66 | @org.codehaus.jackson.annotate.JsonProperty("developerName") 67 | public String getDevName() { 68 | return developerName; 69 | } 70 | 71 | @org.codehaus.jackson.annotate.JsonProperty("developerName") 72 | public void setDevName(String devName) { 73 | this.developerName = devName; 74 | } 75 | 76 | /** 77 | * Name of the application. 78 | * @return name 79 | */ 80 | @org.codehaus.jackson.annotate.JsonProperty("name") 81 | public String getName() { 82 | return this.name; 83 | } 84 | 85 | @org.codehaus.jackson.annotate.JsonProperty("name") 86 | public void setName(String name) { 87 | this.name = name; 88 | } 89 | 90 | /** 91 | * Fully qualified canvas URL. Example: https://somedomain.com/canvas.html 92 | * @return canvasUrl 93 | */ 94 | @org.codehaus.jackson.annotate.JsonProperty("canvasUrl") 95 | public String getCanvasUrl() { 96 | return canvasUrl; 97 | } 98 | 99 | @org.codehaus.jackson.annotate.JsonProperty("canvasUrl") 100 | public void setCanvasUrl(String canvasUrl) { 101 | this.canvasUrl = canvasUrl; 102 | } 103 | 104 | /** 105 | * The connected app's application Id. 106 | * @return applicationId 107 | */ 108 | @org.codehaus.jackson.annotate.JsonProperty("applicationId") 109 | public String getApplicationId() { 110 | return applicationId; 111 | } 112 | 113 | @org.codehaus.jackson.annotate.JsonProperty("applicationId") 114 | public void setApplicationId(String applicationId) { 115 | this.applicationId = applicationId; 116 | } 117 | 118 | /** 119 | * The version of the connected app 120 | * @return version information example: "1.0" 121 | */ 122 | @org.codehaus.jackson.annotate.JsonProperty("version") 123 | public String getVersion() { 124 | return version; 125 | } 126 | 127 | @org.codehaus.jackson.annotate.JsonProperty("version") 128 | public void setVersion(String version) { 129 | this.version = version; 130 | } 131 | 132 | /** 133 | * The authType of connected app. Valid values "signed_request" or "oauth". 134 | * @return authType 135 | */ 136 | @org.codehaus.jackson.annotate.JsonProperty("authType") 137 | public String getAuthType() { 138 | return authType; 139 | } 140 | 141 | @org.codehaus.jackson.annotate.JsonProperty("authType") 142 | public void setAuthType(String authType) { 143 | this.authType = authType; 144 | } 145 | 146 | /** 147 | * The customer facing identifier for this canvas application. 148 | */ 149 | @org.codehaus.jackson.annotate.JsonProperty("referenceId") 150 | public String getReferenceId() { 151 | return this.referenceId; 152 | } 153 | 154 | @org.codehaus.jackson.annotate.JsonProperty("referenceId") 155 | public void setReferenceId(String referenceId) { 156 | this.referenceId = referenceId; 157 | } 158 | 159 | /** 160 | * Returns a list of options that have been selected. Example: HideHeader, HideShare 161 | * these are used to suppress the header and footer in the publisher. 162 | */ 163 | @org.codehaus.jackson.annotate.JsonProperty("options") 164 | public List getOptions() { 165 | if (null == this.options){ 166 | this.options = new ArrayList(0); 167 | } 168 | return this.options; 169 | } 170 | 171 | @org.codehaus.jackson.annotate.JsonProperty("options") 172 | public void setOptions(List options) { 173 | this.options = options; 174 | } 175 | 176 | /** 177 | * Property indicating what SAML initiation method was selected if any. 178 | * @return null, "IdpInitiated" or "SpInitiated" 179 | */ 180 | @org.codehaus.jackson.annotate.JsonProperty("samlInitiationMethod") 181 | public String getSamlInitiationMethod() { 182 | return samlInitiationMethod; 183 | } 184 | 185 | @org.codehaus.jackson.annotate.JsonProperty("samlInitiationMethod") 186 | public void setSamlInitiationMethod(String samlInitiationMethod) { 187 | this.samlInitiationMethod = samlInitiationMethod; 188 | } 189 | 190 | 191 | @Override 192 | public String toString() 193 | { 194 | return namespace+ ","+ 195 | developerName+ ","+ 196 | applicationId+ ","+ 197 | version+ ","+ 198 | authType+ ","+ 199 | referenceId + "," + 200 | canvasUrl + "," + 201 | samlInitiationMethod; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/main/java/canvas/CanvasClient.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011-2013, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package canvas; 27 | 28 | /** 29 | * Describes contextual information about the current canvas client (third party app). This Object, 30 | * in JS literal notation, needs to ba passed on all Sfdc.canvas.client requests. 31 | */ 32 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 33 | public class CanvasClient 34 | { 35 | private String OAuthToken; 36 | private String refreshToken; 37 | private String instanceId; 38 | private String targetOrigin; 39 | private String instanceUrl; 40 | 41 | /** 42 | * The scoped OAuth token to be used to subsequent REST calls 43 | */ 44 | @org.codehaus.jackson.annotate.JsonProperty("oauthToken") 45 | public String getOAuthToken() { 46 | return OAuthToken; 47 | } 48 | 49 | /** 50 | * @return The scoped OAuth token to be usd for subsequent REST calls. 51 | */ 52 | @org.codehaus.jackson.annotate.JsonProperty("oauthToken") 53 | public void setOAuthToken(String OAuthToken) { 54 | this.OAuthToken = OAuthToken; 55 | } 56 | 57 | /** 58 | * Gets the refresh token for this user that can be used to 59 | * retrieve a new oauth token. The connected application must 60 | * have the Refresh Token oauth scope set before this will have 61 | * a valid refresh token. 62 | */ 63 | @org.codehaus.jackson.annotate.JsonProperty("refreshToken") 64 | public String getRefreshToken() { 65 | return refreshToken; 66 | } 67 | 68 | /** 69 | * Sets the refresh token for this user that can be used to 70 | * retrieve a new oauth token. 71 | */ 72 | @org.codehaus.jackson.annotate.JsonProperty("refreshToken") 73 | public void setRefreshToken(String refreshToken) { 74 | this.refreshToken = refreshToken; 75 | } 76 | 77 | /** 78 | * Unique identifier for this canvas app. This value will be different for each instance of a canvas app, even if 79 | * the same canvas app is placed on a page more than once. 80 | * @return Unique identifier for this canvas app 81 | */ 82 | @org.codehaus.jackson.annotate.JsonProperty("instanceId") 83 | public String getInstanceId() { 84 | return instanceId; 85 | } 86 | 87 | @org.codehaus.jackson.annotate.JsonProperty("instanceId") 88 | public void setInstanceId(String instanceId) { 89 | this.instanceId = instanceId; 90 | } 91 | 92 | /** 93 | * @returns the origin (http://somesalesforcedomain:port) of the parent to the canvas app. This is used so 94 | * the in browser proxy knows where to post the request to. 95 | */ 96 | @org.codehaus.jackson.annotate.JsonProperty("targetOrigin") 97 | public String getTargetOrigin() { 98 | return this.targetOrigin; 99 | } 100 | 101 | @org.codehaus.jackson.annotate.JsonProperty("targetOrigin") 102 | public void setTargetOrigin(String targetOrigin) { 103 | this.targetOrigin = targetOrigin; 104 | } 105 | 106 | /** 107 | * The base url for all subsequent REST call, this has the correct 108 | * Salesforce instance this organization is pinned to. 109 | */ 110 | @org.codehaus.jackson.annotate.JsonProperty("instanceUrl") 111 | public String getInstanceUrl() { 112 | return instanceUrl; 113 | } 114 | 115 | @org.codehaus.jackson.annotate.JsonProperty("instanceUrl") 116 | public void setInstanceUrl(String instanceUrl) { 117 | this.instanceUrl = instanceUrl; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/canvas/CanvasContext.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011-2013, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package canvas; 27 | 28 | /** 29 | * Describes all contextual information related to canvas applications. 30 | * 31 | *

32 | * Some information within the context depends on what oauth scopes are allowed 33 | * on the canvas application. Some/all items may be null if the oauth scope is 34 | * not set accordingly. 35 | */ 36 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 37 | public class CanvasContext { 38 | private CanvasUserContext userContext = null; 39 | private CanvasOrganizationContext orgContext = null; 40 | private CanvasLinkContext linkContext = null; 41 | private CanvasEnvironmentContext envContext = null; 42 | private CanvasApplicationContext appContext = null; 43 | 44 | /** 45 | * Provides the context about the current user. 46 | * 47 | * @return The current user context, or null if the oauth scope 48 | * will not allow. 49 | */ 50 | @org.codehaus.jackson.annotate.JsonProperty("user") 51 | public CanvasUserContext getUserContext() { 52 | return this.userContext; 53 | } 54 | 55 | /** 56 | * Sets the context about the current user. 57 | */ 58 | @org.codehaus.jackson.annotate.JsonProperty("user") 59 | public void setUserContext(CanvasUserContext userContext) 60 | { 61 | this.userContext = userContext; 62 | } 63 | 64 | /** 65 | * Provides the context about the current organization. 66 | * 67 | * @return The current organization context, or null if the oauth scope 68 | * will not allow. 69 | */ 70 | @org.codehaus.jackson.annotate.JsonProperty("organization") 71 | public CanvasOrganizationContext getOrganizationContext() { 72 | return orgContext; 73 | } 74 | 75 | /** 76 | * Sets the context about the current organization. 77 | */ 78 | @org.codehaus.jackson.annotate.JsonProperty("organization") 79 | public void setOrganizationContext(CanvasOrganizationContext orgContext) 80 | { 81 | this.orgContext = orgContext; 82 | } 83 | 84 | /** 85 | * Provides the context about the current environment (page, url, etc). 86 | */ 87 | @org.codehaus.jackson.annotate.JsonProperty("environment") 88 | public CanvasEnvironmentContext getEnvironmentContext() { 89 | if (null == this.envContext){ 90 | return new CanvasEnvironmentContext(); 91 | } 92 | return envContext; 93 | } 94 | 95 | @org.codehaus.jackson.annotate.JsonProperty("environment") 96 | public void setEnvironmentContext(CanvasEnvironmentContext envContext){ 97 | this.envContext = envContext; 98 | } 99 | 100 | /** 101 | * Provides links to external resources within sfdc. 102 | */ 103 | @org.codehaus.jackson.annotate.JsonProperty("links") 104 | public CanvasLinkContext getLinkContext() { 105 | return linkContext; 106 | } 107 | 108 | /** 109 | * Sets the link context for this request. 110 | * @param linkContext 111 | */ 112 | @org.codehaus.jackson.annotate.JsonProperty("links") 113 | public void setLinkContext(CanvasLinkContext linkContext) 114 | { 115 | this.linkContext = linkContext; 116 | } 117 | 118 | /** 119 | * Provides application metadata for the canvas application. 120 | */ 121 | @org.codehaus.jackson.annotate.JsonProperty("application") 122 | public CanvasApplicationContext getAppContext() { 123 | return appContext; 124 | } 125 | 126 | /** 127 | * Sets the application context for this request. 128 | * @param appContext 129 | */ 130 | @org.codehaus.jackson.annotate.JsonProperty("application") 131 | public void setAppContext(CanvasApplicationContext appContext) { 132 | this.appContext = appContext; 133 | } 134 | 135 | @Override 136 | public String toString() 137 | { 138 | return String.format("Canvas Context:\n\t" + 139 | "User Context:\n\t\t%s\n\t"+ 140 | "Org Context:\n\t\t%s\n\t"+ 141 | "Environment Context:\n\t\t%s\n\t"+ 142 | "Link Context:\n\t\t%s\n"+ 143 | "App Context:\n\t\t%s\n", 144 | null != userContext?userContext.toString():"null", 145 | null != orgContext?orgContext.toString():"null", 146 | null != envContext?envContext.toString():"null", 147 | null != linkContext?linkContext.toString():"null", 148 | null != appContext?appContext.toString():"null"); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/canvas/CanvasEnvironmentContext.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011-2013, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package canvas; 27 | 28 | import java.util.HashMap; 29 | import java.util.Map; 30 | 31 | /** 32 | * Environmental information about the canvas application. 33 | */ 34 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 35 | public class CanvasEnvironmentContext { 36 | 37 | private String locationUrl; 38 | private String displayLocation; 39 | private String sublocation; 40 | private String uiTheme; 41 | private Dimensions dimensions; 42 | private SystemVersion version; 43 | private Map parameters; 44 | private Map record; 45 | 46 | /** 47 | * Returns the url of the current location. 48 | */ 49 | @org.codehaus.jackson.annotate.JsonProperty("locationUrl") 50 | public String getLocationUrl() { 51 | return this.locationUrl; 52 | } 53 | 54 | @org.codehaus.jackson.annotate.JsonProperty("locationUrl") 55 | public void setLocationUrl(String referrerUrl) { 56 | this.locationUrl = referrerUrl; 57 | } 58 | 59 | /** 60 | * Returns the location where the app is being displayed. Valid locations are selected when 61 | * the app is created. 62 | */ 63 | @org.codehaus.jackson.annotate.JsonProperty("displayLocation") 64 | public String getDisplayLocation() { 65 | return displayLocation; 66 | } 67 | 68 | @org.codehaus.jackson.annotate.JsonProperty("displayLocation") 69 | public void setDisplayLocation(String displayLocation) { 70 | this.displayLocation = displayLocation; 71 | } 72 | 73 | /** 74 | * Returns the sublocation where the app is being displayed. Usually only applies to 75 | * mobile devices. 76 | */ 77 | @org.codehaus.jackson.annotate.JsonProperty("sublocation") 78 | public String getSublocation() { 79 | return sublocation; 80 | } 81 | 82 | @org.codehaus.jackson.annotate.JsonProperty("sublocation") 83 | public void setSublocation(String sublocation) { 84 | this.sublocation = sublocation; 85 | } 86 | 87 | /** 88 | * Returns the value Theme2 if the user is using the newer user interface theme of the online application, labeled 89 | * \u201cSalesforce.\u201d Returns Theme1 if the user is using the older user interface theme, labeled 90 | * \u201cSalesforce Classic.\u201d 91 | * 92 | * @see common.html.styles.UiSkin 93 | */ 94 | @org.codehaus.jackson.annotate.JsonProperty("uiTheme") 95 | public String getUiTheme() { 96 | return this.uiTheme; 97 | } 98 | 99 | @org.codehaus.jackson.annotate.JsonProperty("uiTheme") 100 | public void setUiTheme(String uiTheme) { 101 | this.uiTheme = uiTheme; 102 | } 103 | 104 | @org.codehaus.jackson.annotate.JsonProperty("dimensions") 105 | public Dimensions getDimensions() { 106 | return this.dimensions; 107 | } 108 | 109 | @org.codehaus.jackson.annotate.JsonProperty("dimensions") 110 | public void setDimensions(Dimensions dimensions) { 111 | this.dimensions = dimensions; 112 | } 113 | 114 | @org.codehaus.jackson.annotate.JsonProperty("version") 115 | public SystemVersion getSystemVersion() { 116 | return this.version; 117 | } 118 | 119 | @org.codehaus.jackson.annotate.JsonProperty("version") 120 | public void setSystemVersion(SystemVersion systemVersion) { 121 | this.version = systemVersion; 122 | } 123 | 124 | @org.codehaus.jackson.annotate.JsonProperty("parameters") 125 | public Map getParameters() { 126 | if (null == this.parameters){ 127 | this.parameters = new HashMap(); 128 | } 129 | return this.parameters; 130 | } 131 | 132 | @org.codehaus.jackson.annotate.JsonProperty("parameters") 133 | public void setParameters(Map parameters) { 134 | this.parameters = parameters; 135 | } 136 | 137 | @org.codehaus.jackson.annotate.JsonProperty("record") 138 | public Map getRecord() { 139 | if (null == this.record){ 140 | this.record = new HashMap(); 141 | } 142 | return this.record; 143 | } 144 | 145 | @org.codehaus.jackson.annotate.JsonProperty("record") 146 | public void setRecord(Map record) { 147 | this.record = record; 148 | } 149 | 150 | @Override 151 | public String toString() 152 | { 153 | return locationUrl + ", " + 154 | displayLocation + ", " + 155 | uiTheme + "," + 156 | dimensions.toString() + "," + 157 | getParameters().toString() + "," + 158 | version.toString(); 159 | } 160 | 161 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 162 | public static class Dimensions{ 163 | /** 164 | * The width of the iframe 165 | */ 166 | private String width; 167 | /** 168 | * The height of the iframe. 169 | */ 170 | private String height; 171 | 172 | /** 173 | * The max width of the iframe 174 | */ 175 | private String maxWidth; 176 | /** 177 | * The max height of the iframe. 178 | */ 179 | private String maxHeight; 180 | 181 | /** 182 | * The width of the iframe's container element. 183 | * For example, the div element's HTMLElement.clientWidth. 184 | */ 185 | private String clientWidth; 186 | /** 187 | * The height of the iframe's container element. 188 | * For example, the div element's HTMLElement.clientHeight. 189 | */ 190 | private String clientHeight; 191 | 192 | 193 | @org.codehaus.jackson.annotate.JsonProperty("width") 194 | public String getWidth() { 195 | return this.width; 196 | } 197 | @org.codehaus.jackson.annotate.JsonProperty("width") 198 | public void setWidth(String width) { 199 | this.width = width; 200 | } 201 | 202 | @org.codehaus.jackson.annotate.JsonProperty("height") 203 | public String getHeight() { 204 | return this.height; 205 | } 206 | @org.codehaus.jackson.annotate.JsonProperty("height") 207 | public void setHeight(String height) { 208 | this.height = height; 209 | } 210 | 211 | @org.codehaus.jackson.annotate.JsonProperty("maxWidth") 212 | public String getMaxWidth() { 213 | return maxWidth; 214 | } 215 | 216 | @org.codehaus.jackson.annotate.JsonProperty("maxWidth") 217 | public void setMaxWidth(String maxWidth) { 218 | this.maxWidth = maxWidth; 219 | } 220 | 221 | @org.codehaus.jackson.annotate.JsonProperty("maxHeight") 222 | public String getMaxHeight() { 223 | return maxHeight; 224 | } 225 | 226 | @org.codehaus.jackson.annotate.JsonProperty("maxHeight") 227 | public void setMaxHeight(String maxHeight) { 228 | this.maxHeight = maxHeight; 229 | } 230 | 231 | @org.codehaus.jackson.annotate.JsonProperty("clientWidth") 232 | public String getClientWidth() { 233 | return clientWidth; 234 | } 235 | 236 | @org.codehaus.jackson.annotate.JsonProperty("clientWidth") 237 | public void setClientWidth(String clientWidth) { 238 | this.clientWidth = clientWidth; 239 | } 240 | 241 | @org.codehaus.jackson.annotate.JsonProperty("clientHeight") 242 | public String getClientHeight() { 243 | return clientHeight; 244 | } 245 | 246 | @org.codehaus.jackson.annotate.JsonProperty("clientHeight") 247 | public void setClientHeight(String clientHeight) { 248 | this.clientHeight = clientHeight; 249 | } 250 | 251 | @Override 252 | public String toString(){ 253 | return String.format("(w:%s,h:%s,mw:%s,mh:%s,cw:%s,ch:%s)",width,height,maxWidth,maxHeight,clientWidth,clientHeight); 254 | } 255 | } 256 | 257 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 258 | public static class SystemVersion{ 259 | 260 | private String api; 261 | private String season; 262 | 263 | // Needs default ctor for Jackson to construct. 264 | public SystemVersion(){ 265 | } 266 | 267 | @org.codehaus.jackson.annotate.JsonProperty("api") 268 | public String getApiVersion() { 269 | return this.api; 270 | } 271 | 272 | @org.codehaus.jackson.annotate.JsonProperty("api") 273 | public void setApiVersion(String apiVersion) { 274 | this.api = apiVersion; 275 | } 276 | 277 | @org.codehaus.jackson.annotate.JsonProperty("season") 278 | public String getSeason() { 279 | return this.season; 280 | } 281 | 282 | @org.codehaus.jackson.annotate.JsonProperty("season") 283 | public void setSeason(String season) { 284 | this.season = season; 285 | } 286 | 287 | @Override 288 | public String toString(){ 289 | return String.format("%s - %s",api,season); 290 | } 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /src/main/java/canvas/CanvasLinkContext.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011-2013, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package canvas; 27 | 28 | /** 29 | * Describes all contextual information around external references, or links to external resources. 30 | */ 31 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 32 | public class CanvasLinkContext { 33 | private String loginUrl; 34 | private String enterpriseUrl; 35 | private String metadataUrl; 36 | private String partnerUrl; 37 | private String restUrl; 38 | private String sobjectUrl; 39 | private String searchUrl; 40 | private String queryUrl; 41 | private String recentItemsUrl; 42 | private String userProfileUrl; 43 | private String chatterFeedsUrl; 44 | private String chatterGroupsUrl; 45 | private String chatterUsersUrl; 46 | private String chatterFeedItemsUrl; 47 | 48 | /** 49 | * Provide the url for enterprise-wide external clients. 50 | */ 51 | @org.codehaus.jackson.annotate.JsonProperty("enterpriseUrl") 52 | public String getEnterpriseUrl() { 53 | return this.enterpriseUrl; 54 | } 55 | 56 | public void setEnterpriseUrl(String enterpriseUrl) { 57 | this.enterpriseUrl = enterpriseUrl; 58 | } 59 | 60 | /** 61 | * Provide the base url for the metadata api to access information about custom objects, apex classes, etc. 62 | */ 63 | @org.codehaus.jackson.annotate.JsonProperty("metadataUrl") 64 | public String getMetadataUrl() { 65 | return this.metadataUrl; 66 | } 67 | 68 | public void setMetadataUrl(String metadataUrl) { 69 | this.metadataUrl = metadataUrl; 70 | } 71 | 72 | /** 73 | * Access to the partner api for developing client applications for multiple organizations. 74 | */ 75 | @org.codehaus.jackson.annotate.JsonProperty("partnerUrl") 76 | public String getPartnerUrl() { 77 | return this.partnerUrl; 78 | } 79 | 80 | public void setPartnerUrl(String partnerUrl) { 81 | this.partnerUrl = partnerUrl; 82 | } 83 | 84 | /** 85 | * Access to the base url for RESTful services. 86 | */ 87 | @org.codehaus.jackson.annotate.JsonProperty("restUrl") 88 | public String getRestUrl() { 89 | return this.restUrl; 90 | } 91 | 92 | public void setRestUrl(String restUrl) { 93 | this.restUrl = restUrl; 94 | } 95 | 96 | /** 97 | * Access to custom sobject definitions. 98 | */ 99 | @org.codehaus.jackson.annotate.JsonProperty("sobjectUrl") 100 | public String getSobjectUrl() { 101 | return this.sobjectUrl; 102 | } 103 | 104 | public void setSobjectUrl(String sobjectUrl) { 105 | this.sobjectUrl = sobjectUrl; 106 | } 107 | 108 | /** 109 | * Access to search api. 110 | */ 111 | @org.codehaus.jackson.annotate.JsonProperty("searchUrl") 112 | public String getSearchUrl() { 113 | return this.searchUrl; 114 | } 115 | 116 | public void setSearchUrl(String searchUrl) { 117 | this.searchUrl = searchUrl; 118 | } 119 | 120 | /** 121 | * Access to the SOQL query api. 122 | */ 123 | @org.codehaus.jackson.annotate.JsonProperty("queryUrl") 124 | public String getQueryUrl() { 125 | return this.queryUrl; 126 | } 127 | 128 | public void setQueryUrl(String queryUrl) { 129 | this.queryUrl = queryUrl; 130 | } 131 | 132 | /** 133 | * Access to the recent items feed. 134 | */ 135 | @org.codehaus.jackson.annotate.JsonProperty("recentItemsUrl") 136 | public String getRecentItemsUrl() { 137 | return this.recentItemsUrl; 138 | } 139 | 140 | public void setRecentItemsUrl(String recentItemsUrl) { 141 | this.recentItemsUrl = recentItemsUrl; 142 | } 143 | 144 | /** 145 | * Retrieve more information about the current user. 146 | */ 147 | @org.codehaus.jackson.annotate.JsonProperty("userUrl") 148 | public String getUserUrl() { 149 | return this.userProfileUrl; 150 | } 151 | 152 | public void setUserUrl(String userProfileUrl) { 153 | this.userProfileUrl = userProfileUrl; 154 | } 155 | 156 | /** 157 | * Access to Chatter Feeds. Note: Requires user profile permissions, otherwise this will be null. 158 | */ 159 | @org.codehaus.jackson.annotate.JsonProperty("chatterFeedsUrl") 160 | public String getChatterFeedsUrl() { 161 | return this.chatterFeedsUrl; 162 | } 163 | 164 | public void setChatterFeedsUrl(String chatterFeedsUrl) { 165 | this.chatterFeedsUrl = chatterFeedsUrl; 166 | } 167 | 168 | /** 169 | * Access to Chatter Groups. Note: Requires user profile permissions, otherwise this will be null. 170 | */ 171 | @org.codehaus.jackson.annotate.JsonProperty("chatterGroupsUrl") 172 | public String getChatterGroupsUrl() { 173 | return this.chatterGroupsUrl; 174 | } 175 | 176 | public void setChatterGroupsUrl(String chatterGroupsUrl) { 177 | this.chatterGroupsUrl = chatterGroupsUrl; 178 | } 179 | 180 | /** 181 | * Access to Chatter Users. Note: Requires user profile permissions, otherwise this will be null. 182 | */ 183 | @org.codehaus.jackson.annotate.JsonProperty("chatterUsersUrl") 184 | public String getChatterUsersUrl() { 185 | return this.chatterUsersUrl; 186 | } 187 | 188 | public void setChatterUsersUrl(String chatterUsersUrl) { 189 | this.chatterUsersUrl = chatterUsersUrl; 190 | } 191 | 192 | /** 193 | * Access to individual Chatter Feed items. Note: Requires user profile permissions, otherwise this will be null. 194 | */ 195 | @org.codehaus.jackson.annotate.JsonProperty("chatterFeedItemsUrl") 196 | public String getChatterFeedItemsUrl() { 197 | return this.chatterFeedItemsUrl; 198 | } 199 | 200 | public void setChatterFeedItemsUrl(String chatterFeedItemsUrl) { 201 | this.chatterFeedItemsUrl = chatterFeedItemsUrl; 202 | } 203 | 204 | 205 | /** 206 | * The login url used to service OAuth requests. Third party apps would use this url 207 | * to obtain refresh token, or perform normal OAuth flow. 208 | */ 209 | @org.codehaus.jackson.annotate.JsonProperty("loginUrl") 210 | public String getLoginUrl() { 211 | return this.loginUrl; 212 | } 213 | 214 | @org.codehaus.jackson.annotate.JsonProperty("loginUrl") 215 | public void setLoginUrl(String loginUrl) { 216 | this.loginUrl = loginUrl; 217 | } 218 | 219 | @Override 220 | public String toString() 221 | { 222 | return loginUrl + ", " + 223 | enterpriseUrl+ ", " + 224 | metadataUrl+ ", " + 225 | partnerUrl+ ", " + 226 | restUrl+ ", " + 227 | sobjectUrl+ ", " + 228 | searchUrl+ ", " + 229 | queryUrl+ ", " + 230 | recentItemsUrl+ ", " + 231 | userProfileUrl+ ", " + 232 | chatterFeedsUrl+ ", " + 233 | chatterGroupsUrl+ ", " + 234 | chatterUsersUrl+ ", " + 235 | chatterFeedItemsUrl; 236 | } 237 | 238 | } 239 | -------------------------------------------------------------------------------- /src/main/java/canvas/CanvasOrganizationContext.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011-2013, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package canvas; 27 | 28 | /** 29 | * Describes contextual information about the current organization/company. 30 | */ 31 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 32 | public class CanvasOrganizationContext { 33 | private String organizationId; 34 | private String name; 35 | private boolean multicurrencyEnabled; 36 | private String currencyISOCode; 37 | private String namespacePrefix; 38 | 39 | /** 40 | * The organization id of the organization. 41 | */ 42 | @org.codehaus.jackson.annotate.JsonProperty("organizationId") 43 | public String getOrganizationId() { 44 | return this.organizationId; 45 | } 46 | 47 | public void setOrganizationId(String organizationId) { 48 | this.organizationId = organizationId; 49 | } 50 | 51 | /** 52 | * The name of the company or organization. 53 | */ 54 | @org.codehaus.jackson.annotate.JsonProperty("name") 55 | public String getName() { 56 | return this.name; 57 | } 58 | 59 | public void setName(String name) { 60 | this.name = name; 61 | } 62 | 63 | /** 64 | * Indicates whether the user\u2019s organization uses multiple currencies (true) or not (false). 65 | */ 66 | @org.codehaus.jackson.annotate.JsonProperty("multicurrencyEnabled") 67 | public boolean isMulticurrencyEnabled() { 68 | return this.multicurrencyEnabled; 69 | } 70 | 71 | public void setMulticurrencyEnabled(boolean multicurrencyEnabled) { 72 | this.multicurrencyEnabled = multicurrencyEnabled; 73 | } 74 | 75 | /** 76 | * Current company's default currency ISO code (applies only if multi-currency is disabled for the org). 77 | */ 78 | @org.codehaus.jackson.annotate.JsonProperty("currencyIsoCode") 79 | public String getCurrencyISOCode() { 80 | return this.currencyISOCode; 81 | } 82 | 83 | public void setCurrencyISOCode(String currencyISOCode) { 84 | this.currencyISOCode = currencyISOCode; 85 | } 86 | 87 | 88 | @org.codehaus.jackson.annotate.JsonProperty("namespacePrefix") 89 | public String getNamespacePrefix() { 90 | return this.namespacePrefix; 91 | } 92 | 93 | public void setNamespacePrefix(String namespacePrefix) { 94 | this.namespacePrefix = namespacePrefix; 95 | } 96 | 97 | @Override 98 | public String toString() 99 | { 100 | return organizationId + ","+ 101 | name + ","+ 102 | multicurrencyEnabled + ","+ 103 | currencyISOCode + "," + 104 | namespacePrefix; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/canvas/CanvasRequest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011-2013, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package canvas; 27 | 28 | /** 29 | * 30 | * The canvas request is what is sent to the client on the very first request. In this canvas 31 | * request is information for authenticating and context about the user, organization and environment. 32 | *

33 | * This class is serialized into JSON on then signed by the signature service to prevent tampering. 34 | */ 35 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 36 | public class CanvasRequest { 37 | 38 | private String algorithm; 39 | private Integer issuedAt; 40 | private String userId; 41 | private CanvasContext canvasContext; 42 | private CanvasClient client; 43 | 44 | /** 45 | * The algorithm used to sign the request. typically HMAC-SHA256 46 | * @see force.canvas.service.SignRequestService.ALGORITHM 47 | */ 48 | @org.codehaus.jackson.annotate.JsonProperty("algorithm") 49 | public String getAlgorithm() { 50 | return algorithm; 51 | } 52 | 53 | @org.codehaus.jackson.annotate.JsonProperty("algorithm") 54 | public void setAlgorithm(String algorithm) { 55 | this.algorithm = algorithm; 56 | } 57 | 58 | /** 59 | * The unix time this request was issued at. 60 | */ 61 | @org.codehaus.jackson.annotate.JsonProperty("issuedAt") 62 | public Integer getIssuedAt() { 63 | return issuedAt; 64 | } 65 | 66 | @org.codehaus.jackson.annotate.JsonProperty("issuedAt") 67 | public void setIssuedAt(Integer issuedAt) { 68 | this.issuedAt = issuedAt; 69 | } 70 | 71 | /** 72 | * The Salesforce unique id for this user. 73 | * @return 74 | */ 75 | @org.codehaus.jackson.annotate.JsonProperty("userId") 76 | public String getUserId() { 77 | return userId; 78 | } 79 | 80 | @org.codehaus.jackson.annotate.JsonProperty("userId") 81 | public void setUserId(String userId) { 82 | this.userId = userId; 83 | } 84 | 85 | /** 86 | * Context information about the user, org and environment. 87 | */ 88 | @org.codehaus.jackson.annotate.JsonProperty("context") 89 | public CanvasContext getContext() { 90 | return canvasContext; 91 | } 92 | 93 | /** 94 | * Client instance information required while using the Sfdc.canvas.client JavaScript API. 95 | */ 96 | @org.codehaus.jackson.annotate.JsonProperty("context") 97 | public void setContext(CanvasContext canvasContext) { 98 | this.canvasContext = canvasContext; 99 | } 100 | 101 | /** 102 | * Client information passed from client to server. Contains authorization information 103 | * and instance information. 104 | */ 105 | @org.codehaus.jackson.annotate.JsonProperty("client") 106 | public CanvasClient getClient() { 107 | return client; 108 | } 109 | 110 | @org.codehaus.jackson.annotate.JsonProperty("client") 111 | public void setClient(CanvasClient client) { 112 | this.client = client; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/canvas/CanvasUserContext.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011-2013, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package canvas; 27 | 28 | import java.util.Locale; 29 | 30 | /** 31 | * Describes contextual information about the current user. 32 | */ 33 | @org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown=true) 34 | public class CanvasUserContext{ 35 | 36 | private String userId; 37 | private String userName; 38 | private String firstName; 39 | private String lastName; 40 | private String email; 41 | private String fullName; 42 | private Locale locale; 43 | private Locale language; 44 | private String timeZone; 45 | private String profileId; 46 | private String roleId; 47 | private String userType; 48 | private String currencyISOCode; 49 | private boolean accessibilityMode; 50 | private String profilePhotoUrl; 51 | private String profileThumbnailUrl; 52 | 53 | private String siteUrl; 54 | private String siteUrlPrefix; 55 | private boolean isDefaultNetwork; 56 | private String networkId; 57 | 58 | /** 59 | * The Salesforce user identifier. 60 | */ 61 | @org.codehaus.jackson.annotate.JsonProperty("userId") 62 | public String getUserId(){ 63 | return this.userId; 64 | } 65 | 66 | public void setUserId(String userId){ 67 | this.userId = userId; 68 | } 69 | 70 | /** 71 | * The Salesforce username. 72 | */ 73 | @org.codehaus.jackson.annotate.JsonProperty("userName") 74 | public String getUserName(){ 75 | return this.userName; 76 | } 77 | 78 | public void setUserName(String username){ 79 | this.userName = username; 80 | } 81 | 82 | /** 83 | * User's first name. 84 | */ 85 | @org.codehaus.jackson.annotate.JsonProperty("firstName") 86 | public String getFirstName(){ 87 | return this.firstName; 88 | } 89 | 90 | public void setFirstName(String firstName){ 91 | this.firstName = firstName; 92 | } 93 | 94 | /** 95 | * User's last name. 96 | */ 97 | @org.codehaus.jackson.annotate.JsonProperty("lastName") 98 | public String getLastName(){ 99 | return this.lastName; 100 | } 101 | 102 | public void setLastName(String lastName){ 103 | this.lastName = lastName; 104 | } 105 | 106 | /** 107 | * Indicates whether user interface modifications for the visually impaired are on (true) or off (false). 108 | */ 109 | @org.codehaus.jackson.annotate.JsonProperty("accessibilityModeEnabled") 110 | public boolean isAccessibilityMode(){ 111 | return this.accessibilityMode; 112 | } 113 | 114 | public void setAccessibilityMode(boolean accessibilityMode){ 115 | this.accessibilityMode = accessibilityMode; 116 | } 117 | 118 | /** 119 | * The user's email address. 120 | */ 121 | @org.codehaus.jackson.annotate.JsonProperty("email") 122 | public String getEmail(){ 123 | return this.email; 124 | } 125 | 126 | public void setEmail(String email){ 127 | this.email = email; 128 | } 129 | 130 | /** 131 | * User's full name. 132 | */ 133 | @org.codehaus.jackson.annotate.JsonProperty("fullName") 134 | public String getFullName(){ 135 | return this.fullName; 136 | } 137 | 138 | public void setFullName(String fullName){ 139 | this.fullName = fullName; 140 | } 141 | 142 | /** 143 | * User\u2019s locale, which controls the formatting of dates and choice of symbols for currency. 144 | */ 145 | @org.codehaus.jackson.annotate.JsonProperty("locale") 146 | public Locale getLocale(){ 147 | return this.locale; 148 | } 149 | 150 | public void setLocale(Locale locale){ 151 | this.locale = locale; 152 | } 153 | 154 | /** 155 | * User's language, which controls the language for labels displayed in an application. 156 | */ 157 | @org.codehaus.jackson.annotate.JsonProperty("language") 158 | public Locale getLanguage(){ 159 | return this.language; 160 | } 161 | 162 | public void setLanguage(Locale language){ 163 | this.language = language; 164 | } 165 | 166 | /** 167 | * The user's configured timezone. 168 | */ 169 | @org.codehaus.jackson.annotate.JsonProperty("timeZone") 170 | public String getTimeZone(){ 171 | return this.timeZone; 172 | } 173 | 174 | public void setTimeZone(String timezone){ 175 | this.timeZone = timezone; 176 | } 177 | 178 | /** 179 | * Information about the user's profile identifier. 180 | */ 181 | @org.codehaus.jackson.annotate.JsonProperty("profileId") 182 | public String getProfileId(){ 183 | return this.profileId; 184 | } 185 | 186 | public void setProfileId(String profileId){ 187 | this.profileId = profileId; 188 | } 189 | 190 | /** 191 | * Role ID of the role currently assigned to the user. 192 | */ 193 | @org.codehaus.jackson.annotate.JsonProperty("roleId") 194 | public String getRoleId(){ 195 | return this.roleId; 196 | } 197 | 198 | public void setRoleId(String roleId){ 199 | this.roleId = roleId; 200 | } 201 | 202 | /** 203 | * Current user's license type in label form. 204 | */ 205 | public String getUserType(){ 206 | return this.userType; 207 | } 208 | 209 | public void setUserType(String userType){ 210 | this.userType = userType; 211 | } 212 | 213 | /** 214 | * Current user's default currency ISO code (applies only if multi-currency is enabled for the org). 215 | */ 216 | public String getCurrencyISOCode(){ 217 | return this.currencyISOCode; 218 | } 219 | 220 | public void setCurrencyISOCode(String currencyISOCode){ 221 | this.currencyISOCode = currencyISOCode; 222 | } 223 | 224 | /** 225 | * Returns the full profile photo of the current user. 226 | */ 227 | public String getProfilePhotoUrl(){ 228 | return this.profilePhotoUrl; 229 | } 230 | 231 | public void setProfilePhotoUrl(String profilePhotoUrl){ 232 | this.profilePhotoUrl = profilePhotoUrl; 233 | } 234 | 235 | /** 236 | * Returns the thumbnail photo of the current user. 237 | */ 238 | public String getProfileThumbnailUrl(){ 239 | return this.profileThumbnailUrl; 240 | } 241 | 242 | public void setProfileThumbnailUrl(String profileThumbnailUrl){ 243 | this.profileThumbnailUrl = profileThumbnailUrl; 244 | } 245 | 246 | /** 247 | * Site or a community's path prefix. 248 | */ 249 | public String getSiteUrlPrefix() { 250 | return siteUrlPrefix; 251 | } 252 | 253 | public void setSiteUrlPrefix(String siteUrlPrefix) { 254 | this.siteUrlPrefix = siteUrlPrefix; 255 | } 256 | 257 | /** 258 | * Indicates if the current user is in a default network or in a specific community. 259 | * 260 | */ 261 | @org.codehaus.jackson.annotate.JsonProperty("isDefaultNetwork") 262 | public boolean isDefaultNetwork() { 263 | return isDefaultNetwork; 264 | } 265 | 266 | public void setDefaultNetwork(boolean defaultNetwork) { 267 | isDefaultNetwork = defaultNetwork; 268 | } 269 | 270 | /** 271 | * If user is in a community, this returns that community's network id 272 | */ 273 | public String getNetworkId() { 274 | return networkId; 275 | } 276 | 277 | public void setNetworkId(String networkId) { 278 | this.networkId = networkId; 279 | } 280 | 281 | /** 282 | * If user is in a community, this returns community's custom domain URL (portal domain). 283 | */ 284 | public String getSiteUrl() { 285 | return siteUrl; 286 | } 287 | 288 | public void setSiteUrl(String siteUrl) { 289 | this.siteUrl = siteUrl; 290 | } 291 | 292 | @Override 293 | public String toString() 294 | { 295 | return userId+ ","+ 296 | userName+ ","+ 297 | firstName+","+ 298 | lastName+ ","+ 299 | email+ ","+ 300 | fullName+ ","+ 301 | locale+ ","+ 302 | language+ ","+ 303 | timeZone+ ","+ 304 | profileId+ ","+ 305 | roleId+ ","+ 306 | userType+ ","+ 307 | currencyISOCode+ ","+ 308 | accessibilityMode+ ","+ 309 | profilePhotoUrl+","+ 310 | profileThumbnailUrl+","+ 311 | isDefaultNetwork+","+ 312 | networkId+","+ 313 | siteUrlPrefix+","+ 314 | siteUrl+"," 315 | ; 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/main/java/canvas/SignedRequest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package canvas; 28 | 29 | import java.io.IOException; 30 | import java.io.StringWriter; 31 | import java.security.InvalidKeyException; 32 | import java.security.NoSuchAlgorithmException; 33 | import java.util.Arrays; 34 | import java.util.HashMap; 35 | import java.util.regex.Pattern; 36 | 37 | import javax.crypto.Mac; 38 | import javax.crypto.SecretKey; 39 | import javax.crypto.spec.SecretKeySpec; 40 | 41 | import org.apache.commons.codec.binary.Base64; 42 | import org.codehaus.jackson.map.ObjectMapper; 43 | import org.codehaus.jackson.map.ObjectReader; 44 | import org.codehaus.jackson.type.TypeReference; 45 | 46 | /** 47 | * 48 | * The utility method can be used to validate/verify the signed request. In this case, 49 | * the signed request is verified that it is from Salesforce and that it has not been tampered with. 50 | *

51 | * This utility class has two methods. One verifies and decodes the request as a Java object the 52 | * other as a JSON String. 53 | * 54 | */ 55 | public class SignedRequest { 56 | 57 | // Pattern used to escape single quotes so that the browser can parse the json string 58 | // (i.e. John O'leary). 59 | private static final Pattern SINGLE_QUOTE_PATTERN = Pattern.compile("'"); 60 | 61 | public static CanvasRequest verifyAndDecode(String input, String secret) throws SecurityException { 62 | 63 | String[] split = getParts(input); 64 | 65 | String encodedSig = split[0]; 66 | String encodedEnvelope = split[1]; 67 | 68 | // Deserialize the json body 69 | String json_envelope = new String(new Base64(true).decode(encodedEnvelope)); 70 | ObjectMapper mapper = new ObjectMapper(); 71 | ObjectReader reader = mapper.reader(CanvasRequest.class); 72 | CanvasRequest canvasRequest; 73 | String algorithm; 74 | try { 75 | canvasRequest = reader.readValue(json_envelope); 76 | algorithm = canvasRequest.getAlgorithm() == null ? "HMACSHA256" : canvasRequest.getAlgorithm(); 77 | } catch (IOException e) { 78 | throw new SecurityException(String.format("Error [%s] deserializing JSON to Object [%s]", e.getMessage(), CanvasRequest.class.getName()), e); 79 | } 80 | 81 | verify(secret, algorithm, encodedEnvelope, encodedSig); 82 | 83 | // If we got this far, then the request was not tampered with. 84 | // return the request as a Java object 85 | return canvasRequest; 86 | } 87 | 88 | public static String toString(CanvasRequest canvasRequest){ 89 | String rv = null; 90 | if (null != canvasRequest){ 91 | ObjectMapper mapper = new ObjectMapper(); 92 | StringWriter writer; 93 | writer = new StringWriter(); 94 | try { 95 | mapper.writeValue(writer, canvasRequest); 96 | rv = SINGLE_QUOTE_PATTERN.matcher(writer.toString()).replaceAll("\\\\'"); 97 | } catch (Exception e) { 98 | throw new RuntimeException(e); 99 | } 100 | } 101 | return rv; 102 | } 103 | 104 | public static String verifyAndDecodeAsJson(String input, String secret) throws SecurityException { 105 | 106 | String[] split = getParts(input); 107 | 108 | String encodedSig = split[0]; 109 | String encodedEnvelope = split[1]; 110 | 111 | String json_envelope = new String(new Base64(true).decode(encodedEnvelope)); 112 | ObjectMapper mapper = new ObjectMapper(); 113 | 114 | String algorithm; 115 | StringWriter writer; 116 | TypeReference> typeRef 117 | = new TypeReference>() { }; 118 | try { 119 | HashMap o = mapper.readValue(json_envelope, typeRef); 120 | writer = new StringWriter(); 121 | mapper.writeValue(writer, o); 122 | algorithm = (String)o.get("algorithm"); 123 | } catch (IOException e) { 124 | throw new SecurityException(String.format("Error [%s] deserializing JSON to Object [%s]", e.getMessage(), 125 | typeRef.getClass().getName()), e); 126 | } 127 | 128 | verify(secret, algorithm, encodedEnvelope, encodedSig); 129 | 130 | // If we got this far, then the request was not tampered with. 131 | // return the request as a JSON string. 132 | return SINGLE_QUOTE_PATTERN.matcher(writer.toString()).replaceAll("\\\\'"); 133 | } 134 | 135 | private static String[] getParts(String input) { 136 | 137 | if (input == null || input.indexOf(".") <= 0) { 138 | throw new SecurityException(String.format("Input [%s] doesn't look like a signed request", input)); 139 | } 140 | 141 | String[] split = input.split("[.]", 2); 142 | return split; 143 | } 144 | 145 | private static void verify(String secret, String algorithm, String encodedEnvelope, String encodedSig ) 146 | throws SecurityException 147 | { 148 | if (secret == null || secret.trim().length() == 0) { 149 | throw new IllegalArgumentException("secret is null, did you set your environment variable CANVAS_CONSUMER_SECRET?"); 150 | } 151 | 152 | SecretKey hmacKey = null; 153 | try { 154 | byte[] key = secret.getBytes(); 155 | hmacKey = new SecretKeySpec(key, algorithm); 156 | Mac mac = Mac.getInstance(algorithm); 157 | mac.init(hmacKey); 158 | 159 | // Check to see if the body was tampered with 160 | byte[] digest = mac.doFinal(encodedEnvelope.getBytes()); 161 | byte[] decode_sig = new Base64(true).decode(encodedSig); 162 | if (! Arrays.equals(digest, decode_sig)) { 163 | String label = "Warning: Request was tampered with"; 164 | throw new SecurityException(label); 165 | } 166 | } catch (NoSuchAlgorithmException e) { 167 | throw new SecurityException(String.format("Problem with algorithm [%s] Error [%s]", algorithm, e.getMessage()), e); 168 | } catch (InvalidKeyException e) { 169 | throw new SecurityException(String.format("Problem with key [%s] Error [%s]", hmacKey, e.getMessage()), e); 170 | } 171 | 172 | // If we got here and didn't throw a SecurityException then all is good. 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/servlets/AbstractServlet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013 salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package servlets; 27 | 28 | import java.io.IOException; 29 | import java.net.MalformedURLException; 30 | 31 | import javax.servlet.RequestDispatcher; 32 | import javax.servlet.ServletException; 33 | import javax.servlet.http.HttpServlet; 34 | import javax.servlet.http.HttpServletRequest; 35 | import javax.servlet.http.HttpServletResponse; 36 | 37 | public abstract class AbstractServlet 38 | extends HttpServlet{ 39 | 40 | private static final long serialVersionUID = 8014402672778786273L; 41 | 42 | protected void forward(String resource, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { 43 | forward(resource,resource,request,response); 44 | } 45 | 46 | /** 47 | * Forward to a resource in this web-app, defaulting to a resource if the original 48 | * resource does not exist. 49 | */ 50 | protected final void forward(String resource, String defaultResource, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { 51 | if (null == resource){ 52 | throw new IllegalArgumentException("Forward resource not specified."); 53 | } 54 | boolean validResource = resourceExists(resource); 55 | 56 | RequestDispatcher dispatcher = validResource ? getServletContext() 57 | .getRequestDispatcher(resource) : getServletContext() 58 | .getRequestDispatcher(defaultResource); 59 | dispatcher.forward(request, response); 60 | } 61 | 62 | private boolean resourceExists(String path) throws MalformedURLException { 63 | return getServletContext().getResource(path) != null; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/servlets/CallbackController.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013 salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package servlets; 27 | 28 | import java.io.IOException; 29 | 30 | import javax.servlet.ServletException; 31 | import javax.servlet.http.HttpServletRequest; 32 | import javax.servlet.http.HttpServletResponse; 33 | 34 | public class CallbackController 35 | extends AbstractServlet { 36 | private static final String CALLBACK_RESOURCE = "/sdk/callback.html"; 37 | 38 | private static final long serialVersionUID = -7540328539834469665L; 39 | 40 | @Override 41 | protected void doGet(HttpServletRequest request, HttpServletResponse response) 42 | throws ServletException, IOException { 43 | forward(CALLBACK_RESOURCE,request,response); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/servlets/CanvasController.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013 salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package servlets; 27 | 28 | import java.io.IOException; 29 | 30 | import javax.servlet.ServletException; 31 | import javax.servlet.http.HttpServletRequest; 32 | import javax.servlet.http.HttpServletResponse; 33 | 34 | import util.UserAgent; 35 | import canvas.CanvasRequest; 36 | import canvas.SignedRequest; 37 | 38 | /** 39 | * Controller for canvas requests. 40 | *

41 | * This class dispatches the request based on where the canvas application is 42 | * being rendered from. 43 | */ 44 | public class CanvasController extends AbstractServlet { 45 | 46 | public static final String SIGNED_REQUEST_PARAM = "signed_request"; 47 | 48 | /** 49 | * This request parameter is passed when SIGNED_REQUEST is configured 50 | * for the app, but requires some additional information. This can be 51 | * determined on the value on this parameter. 52 | */ 53 | public static final String SFDC_CANVAS_AUTH = "_sfdc_canvas_auth"; 54 | 55 | /** 56 | * This status indicates that the user must approve the app before 57 | * the signed request can be delivered to the app. 58 | * 59 | * @see #SFDC_CANVAS_AUTH 60 | */ 61 | public static final String AUTH_STATUS_USER_APPROVAL_REQUIRED = "user_approval_required"; 62 | 63 | private static final String DEFAULT_RESOURCE = "/default/index.jsp"; 64 | private static final String NO_SIGNED_REQUEST_RESOURCE = "/welcome.jsp"; 65 | private static final String USER_APPROVAL_RESOURCE = "/user-approval.jsp"; 66 | 67 | private static final long serialVersionUID = 2956510495364791829L; 68 | 69 | @Override 70 | protected void service(HttpServletRequest request, 71 | HttpServletResponse response) throws ServletException, IOException { 72 | String srString = request.getParameter(SIGNED_REQUEST_PARAM); 73 | String authStatus = request.getParameter(SFDC_CANVAS_AUTH); 74 | String consumerKey = System.getenv("CANVAS_CONSUMER_KEY"); 75 | 76 | request.setAttribute("ua",UserAgent.parse(request.getHeader("User-Agent"))); 77 | if (null != authStatus && AUTH_STATUS_USER_APPROVAL_REQUIRED.equals(authStatus)){ 78 | if (null == consumerKey || "".equals(consumerKey.trim())){ 79 | throw new IllegalStateException("Consumer key is not defined. Did you forget to set your environment variable, CANVAS_CONSUMER_KEY?"); 80 | } 81 | request.setAttribute("consumerKey", consumerKey); 82 | forward(USER_APPROVAL_RESOURCE, request, response); 83 | return; 84 | } 85 | if (!"POST".equals(request.getMethod())) { 86 | forward(NO_SIGNED_REQUEST_RESOURCE, request, response); 87 | return; 88 | } 89 | if (null == srString) { 90 | forward(NO_SIGNED_REQUEST_RESOURCE, request, response); 91 | return; 92 | } 93 | 94 | CanvasRequest cr = SignedRequest.verifyAndDecode(srString, 95 | System.getenv("CANVAS_CONSUMER_SECRET")); 96 | request.setAttribute("canvasRequest", cr); 97 | request.setAttribute("canvasRequestJson", SignedRequest.toString(cr)); 98 | 99 | String resource = String.format("/%s/index.jsp", cr.getContext() 100 | .getEnvironmentContext().getDisplayLocation()); 101 | forward(resource, request, response); 102 | } 103 | 104 | @Override 105 | protected void forward(String resource, HttpServletRequest request, 106 | HttpServletResponse response) throws IOException, ServletException { 107 | super.forward(resource,DEFAULT_RESOURCE,request,response); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/servlets/OAuthServlet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package servlets; 28 | 29 | import org.apache.commons.httpclient.HttpClient; 30 | import org.apache.commons.httpclient.HttpException; 31 | import org.apache.commons.httpclient.methods.PostMethod; 32 | import org.json.JSONException; 33 | import org.json.JSONObject; 34 | import org.json.JSONTokener; 35 | 36 | import javax.servlet.ServletException; 37 | import javax.servlet.http.HttpServlet; 38 | import javax.servlet.http.HttpServletRequest; 39 | import javax.servlet.http.HttpServletResponse; 40 | import java.io.IOException; 41 | import java.io.InputStreamReader; 42 | import java.io.UnsupportedEncodingException; 43 | import java.net.URLEncoder; 44 | 45 | /** 46 | * A Servlet for handeling OAuth flow. 47 | * This OAuth Servlet is only provided as an example and is provided as-is 48 | */ 49 | public class OAuthServlet extends HttpServlet { 50 | private static final long serialVersionUID = 1L; 51 | 52 | public static final String ACCESS_TOKEN = "ACCESS_TOKEN"; 53 | public static final String INSTANCE_URL = "INSTANCE_URL"; 54 | 55 | private String clientId = null; 56 | private String clientSecret = null; 57 | private String redirectUri = null; 58 | private String authUrl = null; 59 | private String tokenUrl = null; 60 | 61 | public void init() throws ServletException { 62 | 63 | String environment; 64 | 65 | clientId = this.getInitParameter("clientId"); 66 | clientSecret = this.getInitParameter("clientSecret"); 67 | redirectUri = this.getInitParameter("redirectUri"); // https://canvas.herokuapp.com/oauth/_callback 68 | environment = this.getInitParameter("environment"); // https://login.salesforce.com 69 | 70 | try { 71 | authUrl = environment 72 | + "/services/oauth2/authorize?response_type=code&client_id=" 73 | + clientId + "&redirect_uri=" 74 | + URLEncoder.encode(redirectUri, "UTF-8"); 75 | 76 | // Nots: &scope=email,read_chatter,... would be added here for oauth scope 77 | 78 | } catch (UnsupportedEncodingException e) { 79 | throw new ServletException(e); 80 | } 81 | 82 | tokenUrl = environment + "/services/oauth2/token"; 83 | } 84 | 85 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 86 | 87 | System.out.println("Begin OAuth"); 88 | 89 | String accessToken = (String) request.getSession().getAttribute(ACCESS_TOKEN); 90 | 91 | if (accessToken == null) { 92 | 93 | String instanceUrl = null; 94 | 95 | if (request.getRequestURI().endsWith("oauth")) { 96 | // we need to send the user to authorize 97 | response.sendRedirect(authUrl); 98 | return; 99 | } else { 100 | System.out.println("Auth successful - got callback"); 101 | 102 | String code = request.getParameter("code"); 103 | 104 | HttpClient httpclient = new HttpClient(); 105 | 106 | PostMethod post = new PostMethod(tokenUrl); 107 | post.addParameter("code", code); 108 | post.addParameter("grant_type", "authorization_code"); 109 | post.addParameter("client_id", clientId); 110 | post.addParameter("client_secret", clientSecret); 111 | post.addParameter("redirect_uri", redirectUri); 112 | 113 | try { 114 | httpclient.executeMethod(post); 115 | 116 | try { 117 | JSONObject authResponse = new JSONObject( 118 | new JSONTokener(new InputStreamReader( 119 | post.getResponseBodyAsStream()))); 120 | System.out.println("xAuth response: " 121 | + authResponse.toString(2)); 122 | 123 | accessToken = authResponse.getString("access_token"); 124 | 125 | // Instance URL is Salesforce specific. 126 | instanceUrl = authResponse.getString("instance_url"); 127 | 128 | System.out.println("Got access token: " + accessToken); 129 | } catch (JSONException e) { 130 | e.printStackTrace(); 131 | throw new ServletException(e); 132 | } 133 | } catch (HttpException e) { 134 | e.printStackTrace(); 135 | throw new ServletException(e); 136 | } 137 | finally { 138 | post.releaseConnection(); 139 | } 140 | } 141 | 142 | // Set a session attribute so that other servlets can get the access 143 | // token 144 | request.getSession().setAttribute(ACCESS_TOKEN, accessToken); 145 | 146 | // We also get the instance URL from the OAuth response, so set it 147 | // in the session too 148 | request.getSession().setAttribute(INSTANCE_URL, instanceUrl); 149 | } 150 | 151 | response.sendRedirect(request.getContextPath() + "/index.html"); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/servlets/ProxyServlet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2011, salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package servlets; 28 | 29 | import javax.servlet.ServletConfig; 30 | import javax.servlet.ServletException; 31 | import javax.servlet.http.HttpServlet; 32 | import javax.servlet.http.HttpServletRequest; 33 | import javax.servlet.http.HttpServletResponse; 34 | import java.io.IOException; 35 | import java.io.InputStream; 36 | import java.io.OutputStream; 37 | import java.net.HttpURLConnection; 38 | import java.net.URL; 39 | import java.util.Enumeration; 40 | import java.util.List; 41 | import java.util.Map; 42 | 43 | /** 44 | * ServerSide proxy for proxying request to remote server to get around cross domain issues. 45 | * This Proxy is only provided as an example and is provided as-is. 46 | */ 47 | public class ProxyServlet extends HttpServlet { 48 | 49 | // web.xml config parameter names 50 | private static final String INIT_PARAM_CONNECTION_TIMEOUT = "connection_timeout"; 51 | private static final String INIT_PARAM_FOLLOW_REDIRECTS = "follow_redirects"; 52 | private static final String INIT_PARAM_READ_TIMEOUT = "read_timeout"; 53 | private static final String INIT_PARAM_BUFFER_SIZE = "buffer_size"; 54 | private static final String INIT_PARAM_REMOTE_HOST = "remote_host"; 55 | 56 | // Configurable variables in web.xml 57 | private int connectionTimeout; 58 | private boolean followRedirects; 59 | private int readTimeout; 60 | private int bufferSize; 61 | private String remoteHost; 62 | 63 | @Override 64 | public void init(ServletConfig config) throws ServletException { 65 | super.init(config); 66 | connectionTimeout = getConfigParam(INIT_PARAM_CONNECTION_TIMEOUT, 5000); 67 | followRedirects = getConfigParam(INIT_PARAM_FOLLOW_REDIRECTS, true); 68 | readTimeout = getConfigParam(INIT_PARAM_READ_TIMEOUT, 0); 69 | bufferSize = getConfigParam(INIT_PARAM_BUFFER_SIZE, 8 * 1024); 70 | remoteHost = getConfigParam(INIT_PARAM_REMOTE_HOST, null); 71 | } 72 | 73 | @Override 74 | protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 75 | if ("PATCH".equals(request.getMethod())) { 76 | invoke("PATCH", request, response); 77 | } 78 | else { 79 | super.service(request, response); 80 | } 81 | } 82 | 83 | @Override 84 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 85 | invoke("GET", req, resp); 86 | } 87 | 88 | @Override 89 | protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 90 | invoke("PUT", req, resp); 91 | } 92 | 93 | @Override 94 | protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 95 | invoke("DELETE", req, resp); 96 | } 97 | 98 | @Override 99 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 100 | invoke("POST", req, resp); 101 | } 102 | 103 | @Override 104 | protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 105 | invoke("HEAD", req, resp); 106 | } 107 | 108 | @Override 109 | protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 110 | invoke("OPTIONS", req, resp); 111 | } 112 | 113 | protected void invoke(String verb, HttpServletRequest request, HttpServletResponse response) throws IOException 114 | { 115 | if (remoteHost == null) { 116 | response.sendError(HttpServletResponse.SC_BAD_REQUEST, "remote_host not configured"); 117 | return; 118 | } 119 | 120 | String uri = request.getRequestURI(); 121 | String remoteUrl = remoteHost + uri; 122 | 123 | if (request == null || remoteUrl == null || remoteUrl.equalsIgnoreCase(request.getRequestURL().toString())) { 124 | String.format("Bad preconditions remoteUrl [%s] request.getRequestURL() [%s]", remoteUrl, request.getRequestURL().toString()); 125 | return; 126 | } 127 | 128 | // Good to Go.... 129 | 130 | URL url; 131 | HttpURLConnection urlConnection = null; 132 | InputStream inputStream = null; 133 | try 134 | { 135 | //System.out.println("Producer URL: " + remoteUrl); 136 | 137 | url = new URL(remoteUrl); 138 | urlConnection = (HttpURLConnection)url.openConnection(); 139 | 140 | urlConnection.setRequestMethod(verb); 141 | urlConnection.setInstanceFollowRedirects(followRedirects); 142 | urlConnection.setConnectTimeout(connectionTimeout); 143 | urlConnection.setDoInput(true); 144 | urlConnection.setDoOutput(true); 145 | if (readTimeout != 0) urlConnection.setReadTimeout(readTimeout); 146 | 147 | copyRequestHeaders(request, urlConnection); 148 | 149 | if (verb.equals("PUT") || verb.equals("PATCH") || verb.equals("POST") ) { 150 | copyBody(urlConnection, request.getInputStream()); 151 | } 152 | 153 | response.setContentType(urlConnection.getContentType()); 154 | if (! "gzip".equalsIgnoreCase(urlConnection.getContentEncoding())) { 155 | response.setCharacterEncoding(urlConnection.getContentEncoding()); 156 | } 157 | 158 | int responseCode = urlConnection.getResponseCode(); 159 | copyResponseHeaders(response, urlConnection); 160 | 161 | response.setStatus(responseCode); 162 | 163 | int contentLength = urlConnection.getContentLength(); 164 | response.setContentLength(contentLength); 165 | 166 | if (responseCode != HttpURLConnection.HTTP_NOT_MODIFIED) { 167 | OutputStream outputStream = null; 168 | try 169 | { 170 | inputStream = urlConnection.getInputStream(); 171 | outputStream = response.getOutputStream(); 172 | byte buffer[] = new byte[bufferSize]; 173 | while (true) { 174 | int len = inputStream.read(buffer, 0, bufferSize); 175 | if (len < 0) { 176 | break; 177 | } 178 | outputStream.write(buffer, 0, len); 179 | } 180 | } finally { 181 | try { if (outputStream != null) outputStream.flush(); } catch (IOException e) {} 182 | try { if (outputStream != null) outputStream.close(); } catch (IOException e) {} 183 | } 184 | } 185 | 186 | } 187 | finally { 188 | try { if (inputStream != null) inputStream.close(); } catch (IOException e) {} 189 | try { if (urlConnection != null) urlConnection.disconnect(); } catch (Exception e) {} 190 | } 191 | } 192 | 193 | protected void copyBody(HttpURLConnection httpURLConnection, InputStream body) throws IOException 194 | { 195 | OutputStream outputStream = null; 196 | try { 197 | outputStream = httpURLConnection.getOutputStream(); 198 | int val; 199 | while ((val = body.read()) != -1) { 200 | outputStream.write(val); 201 | } 202 | } 203 | finally { 204 | try { if (body != null) body.close(); } catch (IOException e) {} 205 | try { if (outputStream != null) outputStream.flush(); } catch (IOException e) {} 206 | try { if (outputStream != null) outputStream.close(); } catch (IOException e) {} 207 | } 208 | } 209 | 210 | protected void copyRequestHeaders(HttpServletRequest request, HttpURLConnection connection) { 211 | 212 | Enumeration headerNames = request.getHeaderNames(); 213 | while (headerNames.hasMoreElements()) { 214 | 215 | String headerName = (String) headerNames.nextElement(); 216 | Enumeration headerValues = request.getHeaders(headerName); 217 | while (headerValues.hasMoreElements()) { 218 | 219 | String headerValue = (String) headerValues.nextElement(); 220 | if (headerValue != null) { 221 | connection.addRequestProperty(headerName, headerValue); 222 | } 223 | } 224 | } 225 | } 226 | 227 | protected void copyResponseHeaders(HttpServletResponse response, HttpURLConnection connection) { 228 | 229 | Map> headers = connection.getHeaderFields(); 230 | for (String name : headers.keySet()) { 231 | List values = headers.get(name); 232 | 233 | for (int i = 0; i < values.size(); i++) { 234 | String value = values.get(i); 235 | if (name == null || value == null) { 236 | continue; 237 | } 238 | response.addHeader(name, value); 239 | } 240 | } 241 | } 242 | 243 | // Helper methods 244 | private String getConfigParam(String name, String defaultValue) { 245 | String value = getServletConfig().getInitParameter(name); 246 | return (value == null || value.trim().length() == 0) ? defaultValue : value; 247 | } 248 | 249 | private int getConfigParam(String name, int defaultValue) { 250 | String value = getServletConfig().getInitParameter(name); 251 | return (value == null || value.trim().length() == 0) ? defaultValue : Integer.valueOf(value); 252 | } 253 | 254 | private boolean getConfigParam(String name, boolean defaultValue) { 255 | String value = getServletConfig().getInitParameter(name); 256 | return (value == null || value.trim().length() == 0) ? defaultValue : Boolean.valueOf(value); 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/main/java/util/Browser.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013 salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package util; 27 | 28 | /** 29 | * Copyright (c) 2013 salesforce.com, inc. 30 | * All rights reserved. 31 | * 32 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 33 | * that the following conditions are met: 34 | * 35 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 36 | * following disclaimer. 37 | * 38 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 39 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 40 | * 41 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 42 | * promote products derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 45 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 46 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 47 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 48 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 50 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 51 | * POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Simple enum to determine what kind of browser. 56 | */ 57 | public enum Browser{ 58 | IE{ 59 | boolean matches(String ua){ 60 | return ua.contains("msie") || 61 | ua.contains("trident"); 62 | } 63 | }, 64 | FIREFOX{ 65 | boolean matches(String ua){ return ua.contains("firefox");} 66 | }, 67 | SAFARI{ 68 | boolean matches(String ua){return ua.contains("safari");} 69 | }, 70 | GOOGLE_CHROME{ 71 | boolean matches(String ua){return ua.contains("chrome");} 72 | }, 73 | OPERA{ 74 | boolean matches(String ua){ return ua.contains("opera");} 75 | }, 76 | NETSCAPE{ 77 | boolean matches(String ua){ return ua.contains("netscape");} 78 | }, 79 | DESKTOP_WINDOWS{ 80 | boolean matches(String ua){ return ua.contains("windows");} 81 | }, 82 | DESKTOP_LINUX{ 83 | boolean matches(String ua){ return ua.contains("linux");} 84 | }, 85 | UNKNOWN{ // Make sure this is the last value in the enum. 86 | boolean matches(String ua){ return true;} 87 | }; 88 | 89 | public static Browser get(String ua){ 90 | if (null == ua){ 91 | return Browser.UNKNOWN; 92 | } 93 | Browser rv = null; 94 | String uaLower = ua.toLowerCase(); 95 | for(Browser device: Browser.values()){ 96 | if (device.matches(uaLower)){ 97 | rv = device; 98 | break; 99 | } 100 | } 101 | return rv; 102 | } 103 | 104 | abstract boolean matches(String ua); 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/util/Device.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013 salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package util; 27 | import java.util.EnumSet; 28 | import java.util.Set; 29 | 30 | /** 31 | * Copyright (c) 2013 salesforce.com, inc. 32 | * All rights reserved. 33 | * 34 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 35 | * that the following conditions are met: 36 | * 37 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 38 | * following disclaimer. 39 | * 40 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 41 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 42 | * 43 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 44 | * promote products derived from this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 47 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 48 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 49 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 50 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 52 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 53 | * POSSIBILITY OF SUCH DAMAGE. 54 | */ 55 | 56 | /** 57 | * Simple enum to determine what kind of device is hitting this app. 58 | */ 59 | public enum Device{ 60 | IPHONE{ 61 | boolean matches(String ua){ return ua.contains("iphone");} 62 | }, 63 | IPAD{ 64 | boolean matches(String ua){ return ua.contains("ipad");} 65 | }, 66 | ANDROID_PHONE{ 67 | boolean matches(String ua){ 68 | return ua.contains("android") && 69 | ua.contains("mobile"); 70 | } 71 | }, 72 | ANDROID_TABLET{ 73 | boolean matches(String ua){ 74 | return ua.contains("android") && 75 | !ua.contains("mobile"); 76 | } 77 | }, 78 | WINDOWS_PHONE{ 79 | boolean matches(String ua){ return ua.contains("windows phone");} 80 | }, 81 | DESKTOP_MAC{ 82 | boolean matches(String ua){ return ua.contains("macintosh");} 83 | }, 84 | DESKTOP_WINDOWS{ 85 | boolean matches(String ua){ return ua.contains("windows");} 86 | }, 87 | DESKTOP_LINUX{ 88 | boolean matches(String ua){ return ua.contains("linux");} 89 | }, 90 | UNKNOWN{ // Make sure this is the last value in the enum. 91 | boolean matches(String ua){ return true;} 92 | }; 93 | 94 | private static final Set MOBILE_DEVICES = 95 | EnumSet.of(ANDROID_PHONE,IPHONE,WINDOWS_PHONE); 96 | 97 | public static Device get(String ua){ 98 | if (null == ua){ 99 | return Device.UNKNOWN; 100 | } 101 | Device rv = null; 102 | String uaLower = ua.toLowerCase(); 103 | for(Device device: Device.values()){ 104 | if (device.matches(uaLower)){ 105 | rv = device; 106 | break; 107 | } 108 | } 109 | return rv; 110 | } 111 | 112 | public boolean isMobile(){ 113 | return MOBILE_DEVICES.contains(this); 114 | } 115 | 116 | abstract boolean matches(String ua); 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/util/UserAgent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013 salesforce.com, inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | * following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | * the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | * 14 | * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | * promote products derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | package util; 27 | 28 | 29 | /** 30 | * Simple determination of browser user-agents. This obviously can be expanded to include additional information, but 31 | * we are keeping it simple. 32 | */ 33 | public class UserAgent { 34 | 35 | private final Device device; 36 | private final Browser browser; 37 | 38 | public static UserAgent parse(String userAgent){ 39 | return new UserAgent(userAgent); 40 | } 41 | 42 | public Device getDevice(){ 43 | return device; 44 | } 45 | 46 | public Browser getBrowser(){ 47 | return browser; 48 | } 49 | private UserAgent(String userAgent){ 50 | this.device = Device.get(userAgent); 51 | this.browser = Browser.get(userAgent); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/webapp/ChatterFeed/chatterfeed-mobile.css: -------------------------------------------------------------------------------- 1 | @import url("chatterfeed.css"); 2 | /** Add a little bit of padding for mobile devices otherwise it butts up against the side */ 3 | #feed-content { 4 | margin: 5px 0 5px 5px; 5 | } 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/webapp/ChatterFeed/chatterfeed.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Arial", "Helvetica", "sans-serif"; 3 | font-size: 75%; 4 | margin : 0 0 0 0; 5 | } 6 | 7 | #feed { 8 | width: 99%; 9 | height: 98%; 10 | margin: 0 0 0 0; 11 | } 12 | 13 | h3 { 14 | color: #333435; 15 | font-size: 1em; 16 | } 17 | 18 | h4 { 19 | color: darkslategrey; 20 | font-weight: normal; 21 | font-size: 1em; 22 | margin : 0 0 0 0; 23 | } 24 | 25 | ul { 26 | margin : 5px 0 0 0; 27 | } 28 | 29 | #profile-pic { 30 | height: 30px; 31 | width: 30px; 32 | float: left; 33 | } 34 | 35 | .right-just { 36 | overflow: hidden; 37 | display: block; 38 | padding: 0 0 0 10px; 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main/webapp/ChatterFeed/index.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2011, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | <% 27 | if (request.getAttribute("canvasRequest") == null) {%> 28 | This App must be invoked via a signed request!<% 29 | return; 30 | } 31 | %> 32 | 33 | 34 | 35 | Force.com Canvas Java Quick Start 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 55 | 56 | 57 | <%--

--%> 58 |
59 |
60 | 61 |

Welcome to Canvas in the Chatter Feed!

62 |

With Force.com Canvas in the feed, you can:

63 |
    64 |
  • Act on parameters:
  • 65 |
  • Display your 'Live' content.
  • 66 |
  • Use the Canvas SDK to enhance your app
  • 67 |
68 |
69 |
70 | 71 | 72 | -------------------------------------------------------------------------------- /src/main/webapp/MobileNav/index.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2013, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 27 | <%@ page import="canvas.SignedRequest" %> 28 | <% 29 | if (request.getAttribute("canvasRequest") == null) {%> 30 | This App must be invoked via a signed request!<% 31 | return; 32 | } 33 | %> 34 | 35 | 36 | 37 | Force.com Canvas Java Quick Start 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 58 | 59 | 60 |
61 |
62 | 65 |
66 |

With Force.com Canvas in Mobile, you can:

67 |
    68 |
  • Expose your application in Salesforce1, on any client.
  • 69 |
  • Write your application in any language, using "location aware" context information.
  • 70 |
  • Leverage the Force.com Canvas SDK to react to live client-side events, including the Streaming API.
  • 71 |
72 |
73 |
74 | 75 |
76 |
77 |

Powered By: Heroku

78 |
79 |
80 |

Salesforce: SafeHarbor

81 |
82 |
83 |
84 | 85 | 86 | -------------------------------------------------------------------------------- /src/main/webapp/MobileNav/mobile-nav.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | margin-bottom: 0; 4 | margin-top: 0; 5 | padding: 10px; 6 | background-color: #FFFFFF; 7 | font-family: "Arial", "Helvetica", "sans-serif"; 8 | font-size: 75%; 9 | color: #222222 10 | } 11 | 12 | h1 { 13 | font-size: 18px; 14 | color: #000 15 | } 16 | 17 | a { 18 | color: #015BA7 19 | } 20 | 21 | a:hover { 22 | background-color: #015BA7; 23 | color: white; 24 | text-decoration: none 25 | } 26 | 27 | #page { 28 | background-color: #FFFFFF; 29 | width: 100%; 30 | height:100%; 31 | margin: 0; 32 | margin-left: 0; 33 | margin-right: 0; 34 | } 35 | 36 | #content { 37 | background-color: white; 38 | border: 3px solid #aaa; 39 | width: 100%; 40 | height:85%; 41 | } 42 | 43 | #footer { 44 | clear: both 45 | } 46 | 47 | #canvas-content { 48 | padding-top: 25px; 49 | padding-left: 0px; 50 | padding-right: 30px 51 | } 52 | 53 | #header { 54 | background-repeat: no-repeat; 55 | background-position: top left; 56 | padding:0 0 0 75px; 57 | height: 50px; 58 | margin:10px 0 0 20px; 59 | } 60 | 61 | #header h1, #header h2 { 62 | margin: 0 63 | } 64 | 65 | #header h2 { 66 | color: #888; 67 | font-weight: normal; 68 | font-size: 16px 69 | } 70 | 71 | #canvas-content { 72 | border-top: 1px solid #ccc; 73 | padding-top: 10px; 74 | padding-left:10px; 75 | } 76 | 77 | #canvas-content h1 { 78 | margin: 0; 79 | font-size: 12px; 80 | } 81 | 82 | #canvas-content h2 { 83 | margin: 0; 84 | font-size: 12px; 85 | font-weight: normal; 86 | color: #333; 87 | } 88 | 89 | #canvas-content ol { 90 | margin-left: 0; 91 | padding-left: 0 92 | } 93 | 94 | #canvas-content li { 95 | color: #888; 96 | } 97 | 98 | #canvas-content li h2 { 99 | margin: 0; 100 | font-weight: normal; 101 | font-size: 18px; 102 | color: #333 103 | } 104 | 105 | #canvas-content li p { 106 | color: #555; 107 | font-size: 13px 108 | } 109 | 110 | #canvas-chatter { 111 | border-top: 1px solid #ccc; 112 | margin-top: 20px; 113 | padding-top: 0 114 | } 115 | 116 | #speech-input-field { 117 | width: 70%; 118 | height: 14px; 119 | padding: 6px 15px; 120 | border-radius: 10px; 121 | border: 1px solid #ccc; 122 | outline: 0; 123 | } 124 | 125 | button { 126 | clear: both; 127 | width: 48px; 128 | height:24px; 129 | background: #666666 url(/images/share.png) no-repeat; 130 | } 131 | 132 | #footercont 133 | { 134 | float: left; 135 | width: 100%; 136 | height: 20%; 137 | color: #999; 138 | } 139 | 140 | #footercont p 141 | { 142 | margin: 0; 143 | padding: 5px; 144 | } 145 | 146 | #footercont a 147 | { 148 | color: #999; 149 | text-decoration: none; 150 | } 151 | 152 | #footercont a:hover 153 | { 154 | color: #199BD2; 155 | text-decoration: none; 156 | } 157 | 158 | #footerleft 159 | { 160 | float: left; 161 | width: 50%; 162 | } 163 | 164 | #footerright 165 | { 166 | float: left; 167 | width: 50%; 168 | text-align: right; 169 | } 170 | -------------------------------------------------------------------------------- /src/main/webapp/Publisher/index.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2013, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 27 | 28 | 29 | 30 | Force.com Canvas Java Quick Start 31 | 32 | 33 | 34 | 35 | 46 | 47 | 48 | <%--
--%> 49 |
50 |
51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
Name: Location: Subject: Header: Share:
63 |
64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
92 | 93 | 94 | 95 |
96 |
97 |
98 | 99 | 100 | -------------------------------------------------------------------------------- /src/main/webapp/Publisher/publisher-desktop.css: -------------------------------------------------------------------------------- 1 | @import url("publisher.css"); 2 | #publisher-content { 3 | margin-left: 8px; 4 | margin-right: 8px; 5 | } 6 | 7 | .input-iphone { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/webapp/Publisher/publisher-mobile.css: -------------------------------------------------------------------------------- 1 | @import url("publisher.css"); 2 | #publisher-content { 3 | margin-left: 0; 4 | margin-right: 0; 5 | } 6 | 7 | .input-iphone { 8 | width : 100%; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/webapp/Publisher/publisher.css: -------------------------------------------------------------------------------- 1 | html { 2 | width: 100%; 3 | } 4 | 5 | body { 6 | font-family: "Arial", "Helvetica", "sans-serif"; 7 | font-size: 75%; 8 | margin : 0 0 0 0; 9 | width:100%; 10 | } 11 | 12 | #publisher { 13 | width: 100%; 14 | margin: 0 0 0 0; 15 | overflow:auto; 16 | } 17 | 18 | #publisher-canvas-content { 19 | padding-top: 5px; 20 | padding-left: 0; 21 | padding-right: 0; 22 | } 23 | 24 | .input { 25 | border-radius: 3px; 26 | border: 1px solid #c7ccce; 27 | padding: 6px; 28 | outline: 0; 29 | box-sizing: border-box; 30 | margin: 3px 0 6px 0; 31 | } 32 | 33 | #auxText { 34 | width : 100% 35 | } 36 | 37 | #events { 38 | color : green; 39 | } 40 | 41 | .left-label { 42 | float: left; 43 | padding: 7px 0 0 0; 44 | } 45 | 46 | .right-input { 47 | overflow: hidden; 48 | display: block; 49 | padding: 0 0 0 10px; 50 | } 51 | .right-input input { 52 | width: 100% 53 | } 54 | 55 | label { 56 | font-weight: bold; 57 | } 58 | 59 | #description { 60 | width: 100%; 61 | height: 50px; 62 | } 63 | 64 | #parameters { 65 | width: 100%; 66 | height: 30px; 67 | } 68 | 69 | .select { 70 | height: 28px; 71 | } 72 | 73 | .radio-grouping { 74 | display: inline-block; 75 | width: 32%; 76 | } -------------------------------------------------------------------------------- /src/main/webapp/Publisher/publisher.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, salesforce.com, inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without modification, are permitted provided 5 | // that the following conditions are met: 6 | // 7 | // Redistributions of source code must retain the above copyright notice, this list of conditions and the 8 | // following disclaimer. 9 | // 10 | // Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 11 | // the following disclaimer in the documentation and/or other materials provided with the distribution. 12 | // 13 | // Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 14 | // promote products derived from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 17 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 20 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | // POSSIBILITY OF SUCH DAMAGE. 24 | (function ($$){ 25 | 26 | var sr, mobile, postType, thumbnailUrl; 27 | 28 | myPublisher = { 29 | 30 | init : function(signedRequest, isMobile) { 31 | sr = signedRequest; 32 | mobile = isMobile; 33 | }, 34 | 35 | // Auto resize the iframe to fit the current content. 36 | resize : function() { 37 | $$.client.resize(sr.client); 38 | }, 39 | 40 | // Simply display incoming events in order 41 | logEvent : function(name) { 42 | var elem = $$.byId("events"); 43 | var sep = ($$.isNil(elem.value)) ? "" : ","; 44 | elem.value += sep + name 45 | }, 46 | 47 | selectPostType : function(e) { 48 | console.log("got click", e); 49 | postType = e; 50 | // Enable the share button 51 | $$.client.publish(sr.client, {name : "publisher.setValidForSubmit", payload : true}); 52 | }, 53 | 54 | clearPostTypes : function() { 55 | var i, elements = $$.byClass('postType'); 56 | for (i = 0; i < elements.length; i+=1) { 57 | elements[i].checked=false; 58 | } 59 | }, 60 | 61 | canvasOptions : function(elem, option) { 62 | var bool = Sfdc.canvas.indexOf(sr.context.application.options, option) == -1; 63 | elem.innerHTML = (bool) ? "✓" : "✗"; 64 | elem.style.color = (bool) ? "green" : "red"; 65 | }, 66 | 67 | updateContent : function() { 68 | if (!mobile) { 69 | $$.byId('name').innerHTML = sr.context.user.firstName + " " + sr.context.user.lastName; 70 | $$.byId('location').innerHTML = sr.context.environment.displayLocation; 71 | $$.byId('subject-type').innerHTML = null != sr.context.environment.record.attributes ? 72 | sr.context.environment.record.attributes.type : 73 | "Unknown"; 74 | myPublisher.canvasOptions($$.byId('header-enabled'), "HideHeader"); 75 | myPublisher.canvasOptions($$.byId('share-enabled'), "HideShare"); 76 | } 77 | }, 78 | 79 | selectThumbnail: function(e) { 80 | thumbnailUrl = (e === "none") ? null : window.location.origin + e; 81 | console.log("Thumbnail URL " + thumbnailUrl); 82 | }, 83 | 84 | handlers : function() { 85 | 86 | var handlers = { 87 | onSetupPanel : function (payload) { 88 | myPublisher.resize(); // Do I want to do this on iphone? 89 | myPublisher.logEvent("setupPanel"); 90 | }, 91 | onShowPanel : function(payload) { 92 | myPublisher.logEvent("showPanel"); 93 | }, 94 | onClearPanelState : function(payload) { 95 | myPublisher.logEvent("clearPanelState"); 96 | myPublisher.clearPostTypes(); 97 | // Clear all the text fields and reset radio buttons 98 | }, 99 | onSuccess : function() { 100 | myPublisher.logEvent("success"); 101 | }, 102 | onFailure : function (payload) { 103 | myPublisher.logEvent("failure"); 104 | myPublisher.clearPostTypes(); 105 | if (payload && payload.errors && payload.errors.message) { 106 | alert("Error: " + payload.errors.message); 107 | } 108 | }, 109 | onGetPayload : function() { 110 | myPublisher.logEvent("getPayload"); 111 | var p = {}; 112 | if (postType === 'Text') { 113 | // Example of a Text Post 114 | p.feedItemType = "TextPost"; 115 | p.auxText = $$.byId('auxText').value; 116 | } 117 | else if (postType === 'Link') { 118 | // Example of a Link Post 119 | p.feedItemType = "LinkPost"; 120 | p.auxText = $$.byId('auxText').value; 121 | p.url = "http://www.salesforce.com"; 122 | p.urlName = $$.byId('title').value; 123 | } 124 | else if (postType === 'Canvas') { 125 | // Example of a Canvas Post 126 | p.feedItemType = "CanvasPost"; 127 | p.auxText = $$.byId('auxText').value; 128 | p.namespace = sr.context.application.namespace; 129 | p.developerName = sr.context.application.developerName; 130 | p.height = $$.byId('height').value; 131 | p.title = $$.byId('title').value; 132 | p.description = $$.byId('description').value; 133 | p.parameters = $$.byId('parameters').value; 134 | p.thumbnailUrl = thumbnailUrl; 135 | } 136 | $$.client.publish(sr.client, {name : 'publisher.setPayload', payload : p}); 137 | } 138 | }; 139 | 140 | return { 141 | subscriptions : [ 142 | {name : 'publisher.setupPanel', onData : handlers.onSetupPanel}, 143 | {name : 'publisher.showPanel', onData : handlers.onShowPanel}, 144 | {name : 'publisher.clearPanelState', onData : handlers.onClearPanelState}, 145 | {name : 'publisher.failure', onData : handlers.onFailure}, 146 | {name : 'publisher.success', onData : handlers.onSuccess}, 147 | {name : 'publisher.getPayload', onData : handlers.onGetPayload} 148 | ] 149 | }; 150 | } 151 | }; 152 | }(Sfdc.canvas)); 153 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | Heroku Quick Start Template 7 | 8 | 9 | index.html 10 | 11 | 12 | canvas 13 | servlets.CanvasController 14 | 15 | 16 | callback 17 | servlets.CallbackController 18 | 19 | 20 | canvas 21 | /canvas 22 | 23 | 24 | callback 25 | /callback 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/webapp/canvas.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2011, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 27 | <%-- 28 | NOTE: This page is deprecated as of Spring 2014 release, but is here for backward compatibility 29 | purposes. The CanvasController should be used instead which should be mapped to the "/canvas" resource. 30 | --%> 31 | 32 | <%@ page import="java.util.Map" %> 33 | <% 34 | // Pull the signed request out of the request body. 35 | Map parameters = request.getParameterMap(); 36 | String[] signedRequest = parameters.get("signed_request"); 37 | if ("GET".equals(request.getMethod()) || signedRequest == null) {%> 38 | <% 39 | } 40 | else {%> 41 | <% 42 | } 43 | %> 44 | -------------------------------------------------------------------------------- /src/main/webapp/default/api.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2013, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 34 | 35 |

36 | With the Force.com Canvas software development toolkit, working with the Salesforce.com public 37 | Api is easy. 38 |

39 |

40 | For example, you can interact natively with the Chatter Api to create posts and work directly 41 | with the feed. 42 |

43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
Post to Chatter: 
53 |
54 | -------------------------------------------------------------------------------- /src/main/webapp/default/context.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2013, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 27 |

28 | Force.com Canvas delivers user context information directly to your application, complete 29 | with a scoped authentication token to allow your application to communicate with Salesforce.com. 30 |

31 |

32 | Below is a sample of that information: 33 |

34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
First Name: ${canvasRequest.context.userContext.firstName}
Last Name: ${canvasRequest.context.userContext.lastName}
Username: ${canvasRequest.context.userContext.userName}
Email Address: ${canvasRequest.context.userContext.email}
Company: ${canvasRequest.context.organizationContext.name}
You are currently viewing ${canvasRequest.context.environmentContext.record.attributes.type} ${canvasRequest.context.environmentContext.record.Id}
62 | -------------------------------------------------------------------------------- /src/main/webapp/default/default-mobile.css: -------------------------------------------------------------------------------- 1 | @import url("default.css"); 2 | 3 | body{ 4 | width: 100%; 5 | height: 100%; 6 | } 7 | 8 | #resize{ 9 | display:none; 10 | } 11 | 12 | #resize-1{ 13 | display:none; 14 | } 15 | 16 | #canvas-content{ 17 | font-size: 12px; 18 | } 19 | 20 | #header { 21 | height: 50px; 22 | } 23 | 24 | #header h2 { 25 | font-size: 12px; 26 | } 27 | 28 | #header h1 { 29 | font-size: 16px; 30 | } 31 | 32 | #speech-input-field { 33 | width: 100%; 34 | height: 25px; 35 | padding: 0px 0px; 36 | border-radius: 3px; 37 | border: 1px solid #ccc; 38 | outline: 0; 39 | } 40 | 41 | #event-table span textarea{ 42 | font-size:90%; 43 | } 44 | 45 | #event-table span input{ 46 | font-size:90%; 47 | } 48 | 49 | #event-table tr td { 50 | font-size:8px; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /src/main/webapp/default/default.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Arial", "Helvetica", "sans-serif"; 3 | font-size: 90%; 4 | margin: 0 0 0 0; 5 | padding: 0 0 0 0; 6 | } 7 | 8 | h1 { 9 | font-size: 24px; 10 | color: #000 11 | } 12 | 13 | a { 14 | color: #015BA7 15 | } 16 | 17 | a:hover { 18 | background-color: #015BA7; 19 | color: white; 20 | text-decoration: none 21 | } 22 | 23 | #dimensions { 24 | font-family: "Arial", "Helvetica", "sans-serif"; 25 | } 26 | 27 | #content { 28 | float: left; 29 | background-color: white; 30 | border: 1px solid #aaa; 31 | height : 99%; 32 | width : 99%; 33 | } 34 | 35 | #speech-input-field { 36 | width: 350px; 37 | height: 30px; 38 | padding: 6px 15px; 39 | border-radius: 10px; 40 | border: 1px solid #ccc; 41 | outline: 0; 42 | } 43 | 44 | #chatter-submit { 45 | clear: both; 46 | width: 48px; 47 | height:24px; 48 | background: #666666 url(/images/share.png) no-repeat; 49 | } 50 | 51 | #page { 52 | background-color: #FFFFFF; 53 | margin: 0; 54 | margin-left: 0; 55 | margin-right: 0 56 | } 57 | 58 | #footer { 59 | clear: both 60 | } 61 | 62 | #canvas-content { 63 | padding-left: 0px; 64 | padding-right: 30px 65 | } 66 | 67 | #header { 68 | background-repeat: no-repeat; 69 | background-position: top left; 70 | height: 64px; 71 | padding-left: 75px; 72 | margin-left:20px; 73 | } 74 | 75 | #header h2 { 76 | color: #888; 77 | font-weight: normal; 78 | font-size: 16px 79 | } 80 | 81 | #footercont { 82 | float: left; 83 | width: 100%; 84 | height: 40px; 85 | position: absolute; 86 | left: 0; 87 | bottom: 0; 88 | color: #999; 89 | } 90 | 91 | #footercont p { 92 | margin: 0; 93 | padding: 15px; 94 | } 95 | 96 | #footercont a { 97 | color: #999; 98 | text-decoration: none; 99 | } 100 | 101 | #footercont a:hover { 102 | color: #199BD2; 103 | text-decoration: none; 104 | } 105 | 106 | #footerleft { 107 | float: left; 108 | } 109 | 110 | #footerright { 111 | float: right; 112 | text-align: right; 113 | } 114 | 115 | .tabcontent table { 116 | font-size: 85%; 117 | } 118 | 119 | #event-table span { 120 | display: block; 121 | overflow: hidden; 122 | padding: 0 4px 0 0; 123 | } 124 | 125 | #event-table span input { 126 | width: 95%; 127 | } 128 | 129 | #event-table span textarea { 130 | width: 95%; 131 | height: 100%; 132 | overflow-x:auto; 133 | } 134 | 135 | #event-table tr td { 136 | vertical-align:top; 137 | } 138 | 139 | .event-button { 140 | width:100%; 141 | height:15px; 142 | } 143 | -------------------------------------------------------------------------------- /src/main/webapp/default/events.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2013, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 150 | 151 |

152 | Force.com Canvas supports cross-domain eventing between multiple canvas applications. Give it a try... Type in some text and click "Fire!" 153 | to see the event subscription in action! 154 |

155 |

156 | You can also subscribe to custom or other Force.com Canvas events. Enter the event name and click "Subscribe". 157 | Streaming api event names should be in the form 158 | sfdc.streamingapi:/topic/<topic name>. 159 |

160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 |
Enter event text to send:
Subscribe to event:
Current subscriptions:
Event Log: (Clear)
180 | -------------------------------------------------------------------------------- /src/main/webapp/default/index.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2013, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 27 | 28 | 29 | 30 | Force.com Canvas Java Quick Start 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 58 | 59 | 60 | 61 |
62 | 66 | 67 |
68 | Context 69 | Resize 70 | Events 71 | Scrolling 72 | Api 73 |
74 | 75 |
76 | 77 |
78 | 79 |
80 | 81 |
82 | 83 |
84 | 85 |
86 |
87 | 88 |
89 |
90 | 91 |
92 |
93 |
94 |

Powered By: Heroku 95 |

96 |
97 |
98 |

Salesforce: SafeHarbor 99 |

100 |
101 |
102 |
103 | 104 | 105 | -------------------------------------------------------------------------------- /src/main/webapp/default/resize.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2013, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 47 |

48 | Force.com Canvas supports dynamic and automatic resizing so you can manage the size of the Canvas application yourself, 49 | or let Force.com Canvas do all the work. 50 |

51 |

52 | Subscribe to the resize event and see the resize event 53 | in action on the "Events" tab. 54 |

55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
72 | -------------------------------------------------------------------------------- /src/main/webapp/default/scroll.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2013, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 28 |

29 | Force.com Canvas can notify your canvas application when the user scrolls on the outer page. The scroll event is fired with 30 | the right information, so you know exactly where the user is. 31 |

32 |

33 | Subscribe to the scroll event and see how the 34 | scroll event fires on the "Events" tab by scrolling the page. 35 |

36 | -------------------------------------------------------------------------------- /src/main/webapp/default/tabs-mobile.css: -------------------------------------------------------------------------------- 1 | @import url("tabs.css"); 2 | .tabcontent { 3 | padding-top:5px; 4 | padding-left:10px; 5 | font-size:10px; 6 | } 7 | 8 | .tab-box { 9 | padding-bottom:4px; 10 | font-size:10px; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/webapp/default/tabs.css: -------------------------------------------------------------------------------- 1 | .tab-box { 2 | border-bottom: 1px solid #DDD; 3 | padding-bottom:5px; 4 | padding-top:30px; 5 | padding-left:5px; 6 | } 7 | .tab-box a { 8 | border:1px solid #DDD; 9 | color:#666666; 10 | padding: 5px 15px; 11 | text-decoration:none; 12 | background-color: #eee; 13 | } 14 | .tab-box a.activeLink { 15 | background-color: #fff; 16 | border-bottom: 0; 17 | padding: 6px 15px; 18 | } 19 | .tabcontent { 20 | border-top: 0; 21 | padding-top:20px; 22 | padding-left:20px; 23 | height:100%; 24 | } 25 | .hide { display: none;} -------------------------------------------------------------------------------- /src/main/webapp/default/tabs.js: -------------------------------------------------------------------------------- 1 | function selectTab(e) { 2 | var i; 3 | 4 | var tabs = Sfdc.canvas.byClass("tabLink"); 5 | for (i = 0; i < tabs.length; i++ ) { 6 | tabs[i].className = "tabLink"; // this removes "activeLink" 7 | } 8 | var tab = (e.srcElement) ? e.srcElement : e.target; 9 | 10 | if (!tab){ 11 | throw "Unable to determine selected tab."; 12 | } 13 | 14 | Sfdc.canvas.byId(tab.id).className = "tabLink activeLink"; 15 | 16 | var tabcontents = Sfdc.canvas.byClass("tabcontent"); 17 | for (i = 0; i < tabcontents.length; i++ ) { 18 | tabcontents[i].className = "tabcontent paddingAll hide"; 19 | } 20 | Sfdc.canvas.byId(tab.id + "-1").className = "tabcontent paddingAll"; 21 | return false; 22 | } 23 | 24 | function initTabs() { 25 | console.log("init tabs"); 26 | var tabs = Sfdc.canvas.byClass("tabLink"); 27 | for (var i = 0; i < tabs.length; i++ ) { 28 | console.log("Tab " + i); 29 | var fn = tabs[i].onclick; 30 | tabs[i].onclick = function(e){ 31 | if (fn){ 32 | fn(e); 33 | } 34 | selectTab(e); 35 | }; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/webapp/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forcedotcom/canvas-quickstart-java/55642285f71ae42c90f518f8a4ee38afec0f8db0/src/main/webapp/icon.png -------------------------------------------------------------------------------- /src/main/webapp/images/canvaslogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forcedotcom/canvas-quickstart-java/55642285f71ae42c90f518f8a4ee38afec0f8db0/src/main/webapp/images/canvaslogo.png -------------------------------------------------------------------------------- /src/main/webapp/images/salesforce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forcedotcom/canvas-quickstart-java/55642285f71ae42c90f518f8a4ee38afec0f8db0/src/main/webapp/images/salesforce.png -------------------------------------------------------------------------------- /src/main/webapp/images/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forcedotcom/canvas-quickstart-java/55642285f71ae42c90f518f8a4ee38afec0f8db0/src/main/webapp/images/share.png -------------------------------------------------------------------------------- /src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | 26 | 27 | 28 | 29 | Force.com Canvas Java Quick Start 30 | 114 | 115 | 116 |
117 |
118 | 121 |
122 |

123 |
124 | Your sample Java application is up and running. 125 |

126 | For more information on Force.com Canvas Framework, please visit 127 | our developer documentation. 128 |

129 |
130 |
131 | ` 132 | 133 |
134 | 135 | 136 | -------------------------------------------------------------------------------- /src/main/webapp/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forcedotcom/canvas-quickstart-java/55642285f71ae42c90f518f8a4ee38afec0f8db0/src/main/webapp/logo.png -------------------------------------------------------------------------------- /src/main/webapp/scripts/chatter-talk.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, salesforce.com, inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without modification, are permitted provided 5 | // that the following conditions are met: 6 | // 7 | // Redistributions of source code must retain the above copyright notice, this list of conditions and the 8 | // following disclaimer. 9 | // 10 | // Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 11 | // the following disclaimer in the documentation and/or other materials provided with the distribution. 12 | // 13 | // Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 14 | // promote products derived from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 17 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 20 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | // POSSIBILITY OF SUCH DAMAGE. 24 | 25 | 26 | var chatterTalk; 27 | if (!chatterTalk) { 28 | chatterTalk = {}; 29 | } 30 | 31 | (function ($$) { 32 | 33 | "use strict"; 34 | 35 | function onClickHandler() { 36 | } 37 | 38 | chatterTalk.init = function(sr, button, input, callback) { 39 | $$.byId(button).onclick=function() { 40 | var value = $$.byId(input).value; 41 | chatterTalk.post(sr, value, callback); 42 | }; 43 | }; 44 | 45 | 46 | chatterTalk.post = function(sr, message, callback) { 47 | var url = sr.context.links.chatterFeedsUrl+"/news/"+sr.context.user.userId+"/feed-items"; 48 | var body = {body : {messageSegments : [{type: "Text", text: message}]}}; 49 | 50 | $$.client.ajax(url, 51 | {client : sr.client, 52 | method: 'POST', 53 | contentType: "application/json", 54 | data: JSON.stringify(body), 55 | success : function(data) { 56 | if ($$.isFunction(callback)) { 57 | callback(data); 58 | } 59 | } 60 | }); 61 | }; 62 | 63 | }(Sfdc.canvas)); 64 | -------------------------------------------------------------------------------- /src/main/webapp/sdk/callback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Callback Refresh Window 5 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/webapp/sdk/css/canvas.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | margin-bottom: 0; 4 | margin-top: 0; 5 | padding: 10px; 6 | background-color: #FFFFFF; 7 | font-family: "Arial", "Helvetica", "sans-serif"; 8 | font-size: 75%; 9 | color: #222222 10 | } 11 | 12 | h1 { 13 | font-size: 28px; 14 | color: #000 15 | } 16 | 17 | a { 18 | color: #015BA7 19 | } 20 | 21 | a:hover { 22 | background-color: #015BA7; 23 | color: white; 24 | text-decoration: none 25 | } 26 | 27 | #page { 28 | background-color: #FFFFFF; 29 | width: 800px; 30 | margin: 0; 31 | margin-left: 0; 32 | margin-right: 0 33 | } 34 | 35 | #content { 36 | float: left; 37 | background-color: white; 38 | border: 3px solid #aaa; 39 | padding: 25px; 40 | width: 700px 41 | } 42 | 43 | #footer { 44 | clear: both 45 | } 46 | 47 | #header { 48 | padding-left: 75px; 49 | padding-right: 30px 50 | } 51 | 52 | #canvas-content { 53 | padding-top: 25px; 54 | padding-left: 0px; 55 | padding-right: 30px 56 | } 57 | 58 | #header { 59 | background-image: url("/logo.png"); 60 | background-repeat: no-repeat; 61 | background-position: top left; 62 | height: 64px 63 | } 64 | 65 | #header h1, #header h2 { 66 | margin: 0 67 | } 68 | 69 | #header h2 { 70 | color: #888; 71 | font-weight: normal; 72 | font-size: 16px 73 | } 74 | 75 | #canvas-content { 76 | border-top: 1px solid #ccc; 77 | margin-top: 20px; 78 | padding-top: 0 79 | } 80 | 81 | #canvas-content h1 { 82 | margin: 0; 83 | font-size: 20px 84 | } 85 | 86 | #canvas-content h2 { 87 | margin: 0; 88 | font-size: 14px; 89 | font-weight: normal; 90 | color: #333; 91 | margin-bottom: 25px 92 | } 93 | 94 | #canvas-content ol { 95 | margin-left: 0; 96 | padding-left: 0 97 | } 98 | 99 | #canvas-content li { 100 | font-size: 18px; 101 | color: #888; 102 | margin-bottom: 25px 103 | } 104 | 105 | #canvas-content li h2 { 106 | margin: 0; 107 | font-weight: normal; 108 | font-size: 18px; 109 | color: #333 110 | } 111 | 112 | #canvas-content li p { 113 | color: #555; 114 | font-size: 13px 115 | } 116 | 117 | #canvas-chatter { 118 | border-top: 1px solid #ccc; 119 | margin-top: 20px; 120 | padding-top: 0 121 | } 122 | 123 | #speech-input-field { 124 | width: 400px; 125 | height: 14px; 126 | padding: 6px 15px; 127 | border-radius: 10px; 128 | border: 1px solid #ccc; 129 | outline: 0; 130 | } 131 | 132 | button { 133 | clear: both; 134 | width: 48px; 135 | height:24px; 136 | background: #666666 url(/images/share.png) no-repeat; 137 | } 138 | 139 | #footercont 140 | { 141 | float: left; 142 | width: 700px; 143 | height: 50px; 144 | color: #999; 145 | } 146 | 147 | #footercont p 148 | { 149 | margin: 0; 150 | padding: 15px; 151 | } 152 | 153 | #footercont a 154 | { 155 | color: #999; 156 | text-decoration: none; 157 | } 158 | 159 | #footercont a:hover 160 | { 161 | color: #199BD2; 162 | text-decoration: none; 163 | } 164 | 165 | #footerleft 166 | { 167 | float: left; 168 | width: 400px; 169 | height: 50px; 170 | } 171 | 172 | #footerright 173 | { 174 | float: left; 175 | width: 300px; 176 | height: 50px; 177 | text-align: right; 178 | } 179 | -------------------------------------------------------------------------------- /src/main/webapp/signed-request.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2011, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 27 | <%@ page import="canvas.SignedRequest" %> 28 | <%@ page import="java.util.Map" %> 29 | <% 30 | // Pull the signed request out of the request body and verify/decode it. 31 | Map parameters = request.getParameterMap(); 32 | String[] signedRequest = parameters.get("signed_request"); 33 | if (signedRequest == null) {%> 34 | This App must be invoked via a signed request!<% 35 | return; 36 | } 37 | String yourConsumerSecret=System.getenv("CANVAS_CONSUMER_SECRET"); 38 | String signedRequestJson = SignedRequest.verifyAndDecodeAsJson(signedRequest[0], yourConsumerSecret); 39 | %> 40 | 41 | 42 | 43 | Force.com Canvas Java Quick Start 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 83 | 84 | 85 |
86 |
87 | 91 | 92 |
93 |

Canvas Request

94 |

Below is some information received in the Canvas Request:

95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
First Name: Last Name:
Username: Email Address:
Company:
112 |
113 |
114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
Post to Chatter: 
122 |
123 |
124 |
125 | 126 |
127 |
128 |

Powered By: Heroku

129 |
130 |
131 |

Salesforce: SafeHarbor

132 |
133 |
134 |
135 | 136 | 137 | -------------------------------------------------------------------------------- /src/main/webapp/user-approval.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2011, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 27 | <%@ page language="java" contentType="text/html; charset=ISO-8859-1" 28 | pageEncoding="ISO-8859-1"%> 29 | 30 | 31 | 32 | Force.com Canvas Java Quick Start 33 | 34 | 35 | 77 | 78 | 79 |
80 |
81 | 84 |
85 |

86 |
87 | It appears that you have not yet approved this application for use within 88 | Salesforce.com. 89 |

90 | If you are seeing this message, it is because you have either not yet approved this 91 | application, or an administrator has temporarily revoked the ability for this application 92 | to act on your behalf. Click on the "Approve" link below to begin the approval process. 93 |

94 | Approve 95 |

96 |
97 |
98 | ` 99 | 100 |
101 | 102 | 103 | -------------------------------------------------------------------------------- /src/main/webapp/welcome.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Copyright (c) 2011, salesforce.com, inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 12 | the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or 15 | promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | --%> 26 | 27 | <%@ page language="java" contentType="text/html; charset=ISO-8859-1" 28 | pageEncoding="ISO-8859-1"%> 29 | 30 | 31 | 32 | Force.com Canvas Java Quick Start 33 | 34 | 35 | 36 |
37 |
38 | 41 |
42 |

43 |
44 | Your Heroku Java application is up and running. 45 | To see Force.com Canvas Framework specific functionality, please use this app in a Force.com Canvas 46 | enabled organization. 47 |

If you are seeing this page inside of an app within Salesforce, 48 | you must set the "Access Method" for the application to "Signed Request (POST)". 49 |

50 |
51 |
52 | ` 53 | 54 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /system.properties: -------------------------------------------------------------------------------- 1 | java.runtime.version=1.8 2 | --------------------------------------------------------------------------------