I'm unable to figure out why is this code failing, I browsed through Applitools tutorials and I can't figure out what is happening here.
This is the exception being thrown:
com.applitools.eyes.EyesException: eyes.openBase() failed
at com.applitools.eyes.EyesBase.openBase(EyesBase.java:1037)
at com.applitools.eyes.selenium.SeleniumEyes.open(SeleniumEyes.java:246)
at com.applitools.eyes.selenium.Eyes.open(Eyes.java:77)
at com.applitools.eyes.selenium.Eyes.open(Eyes.java:1374)
at BaseTests.validateWindow(BaseTests.java:49)
at SearchTests.testSearchByFullTitle(SearchTests.java:11)
This is SearchTests:
import org.junit.Test;
public class SearchTests extends BaseTests {
#Test
public void testSearchByFullTitle(){
String title = "Agile Testing";
page.search(title);
validateWindow();
}
}
Validate window method:
public void validateWindow(){
eyes.open(driver, "Automation Bookstore", "neka metoda npr: "+
Thread.currentThread().getStackTrace()[2].getMethodName());
eyes.checkWindow();
eyes.close();
}
and the class throwing the exception:
protected void openBase() throws EyesException {
openLogger();
int retry = 0;
do {
try {
if (isDisabled) {
logger.verbose("Ignored");
return;
}
sessionEventHandlers.testStarted(getAUTSessionId());
validateApiKey();
logOpenBase();
validateSessionOpen();
initProviders();
this.isViewportSizeSet = false;
sessionEventHandlers.initStarted();
beforeOpen();
RectangleSize viewportSize = getViewportSizeForOpen();
viewportSizeHandler.set(viewportSize);
try {
if (viewportSize != null) {
ensureRunningSession();
}
} catch (Exception e) {
GeneralUtils.logExceptionStackTrace(logger, e);
retry++;
continue;
}
this.validationId = -1;
isOpen = true;
afterOpen();
return;
} catch (EyesException e) {
logger.log(e.getMessage());
logger.getLogHandler().close();
throw e;
}
} while (MAX_ITERATION > retry);
throw new EyesException("eyes.openBase() failed");
}
After some debugging, I found that I had a typo in my API key. After fixing that, works as expected.
In my case, the same issue was caused by using null as a value for the testName parameter.
I didn't understand it from the beginning, cause I relied on the javadoc for the open function:
/**
* Starts a test.
*
* #param driver The web driver that controls the browser hosting the application under test.
* #param appName The name of the application under test.
* #param testName The test name. (i.e., the visible part of the document's body) or {#code null} to use the current window's viewport.
* #return A wrapped WebDriver which enables SeleniumEyes trigger recording and frame handling.
*/
public WebDriver open(WebDriver driver, String appName, String testName) {
RectangleSize viewportSize = SeleniumEyes.getViewportSize(driver);
this.configuration.setAppName(appName);
this.configuration.setTestName(testName);
this.configuration.setViewportSize(viewportSize);
return open(driver);
}
I am currently building an API gateway for a new microservices system, using the Spring Netflix Zuul library.
So far my gateway contains PRE and POST filters that intercept the requests and perform the required logic, etc.
One thing that I see is that REST calls to specific microservices require invoking an API endpoint (either GET or POST) containing JSON payload data that is very complex.
For an end-user sending a request to a microservice containing this JSON would not be user friendly.
I had an idea such that the API gateway act as a mediator, where the user can submit a more "simplified/ user-friendly" JSON to the API gateway, which will transform the JSON payload with the correct "complex" JSON structure that the target microservice can understand in order to handle the request efficiently.
My understanding of how Netflix Zuul is that this can be done by creating a RouteFilter and then including this logic here.
Can anyone explain if (or how) this transformation could be done using Netflix Zuul?
Any advice is appreciated.
Thanks.
No doubt you can do it with Zuul, i am currently trying to do almost the same. i'd suggest you take a look at this repo :
sample-zuul-filters
and the official doc on github.
Filters have to extend ZuulFilter and implement the following methods :
/**
*return a string defining when your filter must execute during zuul's
*lyfecyle ('pre'/'post' routing
**/
#Override
public String filterType(){
return 'pre'; // run this filter before sending the final request
}
/**
* return an int describing the order that the filter should run on,
* (relative to the other filters and the current 'pre' or 'post' context)
**/
#Override
public int filterOrder {
return 1; //this filter runs first in a pre-request context
}
/**
* return a boolean indicating if the filter should run or not
**/
#Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
if(ctx.getRequest().getRequestURI().equals("/theRouteIWantToFilter"))
{
return true;
}
else {
return false;
}
}
/**
* After all the config stuffs you can set what your filter actually does
* here. This is where your json logic goes.
*/
#Override
public Object run() {
try {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
InputStream stream = ctx.getResponseDataStream();
String body = StreamUtils.copyToString(stream, Charset.forName("UTF-8"));
// transform your json and send it to the api.
ctx.setResponseBody(" Modified body : " + body);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
I am not sure my answer is 100% accurate since i am working on it but it's a start.
I've done payload conversion in pre filter but this should work in route filter as well. Use com.netflix.zuul.http.HttpServletRequestWrapper to capture and modify the original request payload before forwarding the request to target microservice.
Sample code:
package com.sample.zuul.filters.pre;
import com.google.common.io.CharStreams;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.http.HttpServletRequestWrapper;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class JsonConverterFilter extends ZuulFilter {
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 0; // Set it to whatever the order of your filter is
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = new HttpServletRequestWrapper(context.getRequest());
String requestData = null;
JSONParser jsonParser = new JSONParser();
JSONObject requestJson = null;
try {
if (request.getContentLength() > 0) {
requestData = CharStreams.toString(request.getReader());
}
if (requestData == null) {
return null;
}
requestJson = (JSONObject) jsonParser.parse(requestData);
} catch (Exception e) {
//Add your exception handling code here
}
JSONObject modifiedRequest = modifyJSONRequest(requestJson);
final byte[] newRequestDataBytes = modifiedRequest.toJSONString().getBytes();
request = getUpdatedHttpServletRequest(request, newRequestDataBytes);
context.setRequest(request);
return null;
}
private JSONObject modifyJSONRequest(JSONObject requestJSON) {
JSONObject jsonObjectDecryptedPayload = null;
try {
jsonObjectDecryptedPayload = (JSONObject) new JSONParser()
.parse("Your new complex json");
} catch (ParseException e) {
e.printStackTrace();
}
return jsonObjectDecryptedPayload;
}
private HttpServletRequest getUpdatedHttpServletRequest(HttpServletRequest request, final byte[] newRequestDataBytes) {
request = new javax.servlet.http.HttpServletRequestWrapper(request) {
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(
new InputStreamReader(new ByteArrayInputStream(newRequestDataBytes)));
}
#Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStreamWrapper(newRequestDataBytes);
}
/*
* Forcing any calls to HttpServletRequest.getContentLength to return the accurate length of bytes
* from a modified request
*/
#Override
public int getContentLength() {
return newRequestDataBytes.length;
}
};
return request;
}
}
I have a database back-end that I've thoroughly tested with several unit tests. The controller looks like this:
#RequestMapping(value = "/create", method = RequestMethod.POST, produces = "application/json", headers = "content-type=application/json")
public #ResponseBody UserDTO createUser(#RequestBody UserDTO user)
{
UserEntity userEntity = service.add(user);
return mappingUser(userEntity);
}
The unit test looks like:
#Test
public void testCreateUser() throws Exception
{
UserDTO userDto = createUserDto();
String url = BASE_URL + "/rest/users/create";
UserDTO newUserDto = restTemplate
.postForObject(url, userDto, UserDTO.class, new Object[]{});
}
I have confirmed that the unit test works great, and the actual web-service is called correctly, and data is put into the database.
Now, I am using a SmartGWT RestDataSource, and I am trying to configure the RestDataSource correctly to pass a new user in the request body, and return the new object. I want to send the data as JSON in the body, and return JSON from this call. So, it might be that I need to change the controller itself to match up with the datasource.
Here is the AbstractDataSource which extends RestDataSource:
import java.util.Map;
import com.google.gwt.http.client.URL;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.OperationBinding;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.RestDataSource;
import com.smartgwt.client.types.DSOperationType;
import com.smartgwt.client.types.DSProtocol;
public abstract class AbstractRestDataSource extends RestDataSource
{
public AbstractRestDataSource(String id)
{
setID(id);
setClientOnly(false);
// set up FETCH to use GET requests
OperationBinding fetch = new OperationBinding();
fetch.setOperationType(DSOperationType.FETCH);
fetch.setDataProtocol(DSProtocol.GETPARAMS);
DSRequest fetchProps = new DSRequest();
fetchProps.setHttpMethod("GET");
fetch.setRequestProperties(fetchProps);
// set up ADD to use POST requests
OperationBinding add = new OperationBinding();
add.setOperationType(DSOperationType.ADD);
add.setDataProtocol(DSProtocol.POSTMESSAGE);
DSRequest addProps = new DSRequest();
addProps.setHttpMethod("POST");
addProps.setContentType("application/json");
add.setRequestProperties(addProps);
// set up UPDATE to use PUT
OperationBinding update = new OperationBinding();
update.setOperationType(DSOperationType.UPDATE);
update.setDataProtocol(DSProtocol.POSTMESSAGE);
DSRequest updateProps = new DSRequest();
updateProps.setHttpMethod("PUT");
update.setRequestProperties(updateProps);
// set up REMOVE to use DELETE
OperationBinding remove = new OperationBinding();
remove.setOperationType(DSOperationType.REMOVE);
DSRequest removeProps = new DSRequest();
removeProps.setHttpMethod("DELETE");
remove.setRequestProperties(removeProps);
// apply all the operational bindings
setOperationBindings(fetch, add, update, remove);
init();
}
#Override
protected Object transformRequest(DSRequest request)
{
super.transformRequest(request);
// now post process the request for our own means
postProcessTransform(request);
return request.getData();
}
/*
* Implementers can override this method to create a
* different override.
*/
#SuppressWarnings("rawtypes")
protected void postProcessTransform(DSRequest request)
{
StringBuilder url = new StringBuilder(getServiceRoot());
Map dataMap = request.getAttributeAsMap("data");
if (request.getOperationType() == DSOperationType.REMOVE)
{
// in case of remove, append the primary key
url.append(getPrimaryKeyProperty()).append("/").append(dataMap.get(getPrimaryKeyProperty()));
}
else if (request.getOperationType() == DSOperationType.UPDATE)
{
url.append("update");
appendParameters(url, request);
}
else if (request.getOperationType() == DSOperationType.FETCH && dataMap.size() > 0)
{
url.append(getPrimaryKeyProperty()).append("/").append(dataMap.get(getPrimaryKeyProperty()));
}
else if (request.getOperationType() == DSOperationType.ADD)
{
url.append("create");
}
System.out.println("AbstractRestDataSource: postProcessTransform: url=" + url.toString());
request.setActionURL(URL.encode(url.toString()));
}
/*
* This simply appends parameters that have changed to the URL
* so that PUT requests go through successfully. This is usually
* necessary because when smart GWT updates a row using a form,
* it sends the data as form parameters. Most servers cannot
* understand this and will simply disregard the form data
* sent to the server via PUT. So we need to transform the form
* data into URL parameters.
*/
#SuppressWarnings("rawtypes")
protected void appendParameters(StringBuilder url, DSRequest request)
{
Map dataMap = request.getAttributeAsMap("data");
Record oldValues = request.getOldValues();
boolean paramsAppended = false;
if (!dataMap.isEmpty())
{
url.append("?");
}
for (Object keyObj : dataMap.keySet())
{
String key = (String) keyObj;
if (!dataMap.get(key).equals(oldValues.getAttribute(key)) || isPrimaryKey(key))
{
// only append those values that changed or are primary keys
url.append(key).append('=').append(dataMap.get(key)).append('&');
paramsAppended = true;
}
}
if (paramsAppended)
{
// delete the last '&'
url.deleteCharAt(url.length() - 1);
}
}
private boolean isPrimaryKey(String property)
{
return getPrimaryKeyProperty().equals(property);
}
/*
* The implementer can override this to change the name of the
* primary key property.
*/
protected String getPrimaryKeyProperty()
{
return "id";
}
protected abstract String getServiceRoot();
protected abstract void init();
}
And here is the UserDataSource which extends AbstractRestDataSource:
import java.util.Map;
import com.google.gwt.http.client.URL;
import com.opensource.restful.shared.Constants;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.fields.DataSourceBooleanField;
import com.smartgwt.client.data.fields.DataSourceDateField;
import com.smartgwt.client.data.fields.DataSourceIntegerField;
import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.types.DSDataFormat;
import com.smartgwt.client.types.DSOperationType;
public class UserDataSource extends AbstractRestDataSource
{
private static UserDataSource instance = null;
public static UserDataSource getInstance()
{
if (instance == null)
{
instance = new UserDataSource("restUserDS");
}
return instance;
}
private UserDataSource(String id)
{
super(id);
}
private DataSourceIntegerField userIdField;
private DataSourceBooleanField userActiveField;
private DataSourceTextField usernameField;
private DataSourceTextField passwordField;
private DataSourceTextField firstnameField;
private DataSourceTextField lastnameField;
private DataSourceTextField emailField;
private DataSourceTextField securityQuestion1Field;
private DataSourceTextField securityAnswer1Field;
private DataSourceTextField securityQuestion2Field;
private DataSourceTextField securityAnswer2Field;
private DataSourceDateField birthdateField;
private DataSourceIntegerField positionIdField;
protected void init()
{
setDataFormat(DSDataFormat.JSON);
setJsonRecordXPath("/");
// set the values for the datasource
userIdField = new DataSourceIntegerField(Constants.USER_ID, Constants.TITLE_USER_ID);
userIdField.setPrimaryKey(true);
userIdField.setCanEdit(false);
userActiveField = new DataSourceBooleanField(Constants.USER_ACTIVE, Constants.TITLE_USER_ACTIVE);
usernameField = new DataSourceTextField(Constants.USER_USERNAME, Constants.TITLE_USER_USERNAME);
passwordField = new DataSourceTextField(Constants.USER_PASSWORD, Constants.TITLE_USER_PASSWORD);
firstnameField = new DataSourceTextField(Constants.USER_FIRST_NAME, Constants.TITLE_USER_FIRST_NAME);
lastnameField = new DataSourceTextField(Constants.USER_LAST_NAME, Constants.TITLE_USER_LAST_NAME);
emailField = new DataSourceTextField(Constants.USER_EMAIL, Constants.TITLE_USER_EMAIL);
securityQuestion1Field =
new DataSourceTextField(Constants.USER_SECURITY_QUESTION_1, Constants.TITLE_USER_SECURITY_QUESTION_1);
securityAnswer1Field =
new DataSourceTextField(Constants.USER_SECURITY_ANSWER_1, Constants.TITLE_USER_SECURITY_ANSWER_1);
securityQuestion2Field =
new DataSourceTextField(Constants.USER_SECURITY_QUESTION_2, Constants.TITLE_USER_SECURITY_QUESTION_2);
securityAnswer2Field =
new DataSourceTextField(Constants.USER_SECURITY_ANSWER_2, Constants.TITLE_USER_SECURITY_ANSWER_2);
birthdateField = new DataSourceDateField(Constants.USER_BIRTHDATE, Constants.TITLE_USER_BIRTHDATE);
positionIdField = new DataSourceIntegerField(Constants.USER_POSITION_ID, Constants.TITLE_USER_POSITION_ID);
// positionActiveField = new DataSourceBooleanField(Constants.USER_ACTIVE, Constants.TITLE_USER_ACTIVE);
// positionCodeField;
// positionDescriptionField;
setFields(userIdField, userActiveField, usernameField, passwordField, firstnameField, lastnameField,
emailField, birthdateField, securityQuestion1Field, securityAnswer1Field, securityQuestion2Field,
securityAnswer2Field, positionIdField);
}
protected String getServiceRoot()
{
return "rest/users/";
}
protected String getPrimaryKeyProperty()
{
return "userId";
}
/*
* Implementers can override this method to create a
* different override.
*/
#SuppressWarnings("rawtypes")
protected void postProcessTransform(DSRequest request)
{
// request.setContentType("application/json");
StringBuilder url = new StringBuilder(getServiceRoot());
Map dataMap = request.getAttributeAsMap("data");
if (request.getOperationType() == DSOperationType.REMOVE)
{
// in case of remove, append the primary key
url.append(getPrimaryKeyProperty()).append("/").append(dataMap.get(getPrimaryKeyProperty()));
}
else if (request.getOperationType() == DSOperationType.UPDATE)
{
url.append("update");
System.out.println("UserDataSource: postProcessTransform: update: url=" + url.toString());
}
else if (request.getOperationType() == DSOperationType.FETCH && dataMap.size() > 0)
{
url.append(getPrimaryKeyProperty()).append("/").append(dataMap.get(getPrimaryKeyProperty()));
}
else if (request.getOperationType() == DSOperationType.ADD)
{
url.append("create");
}
System.out.println("UserDataSource: postProcessTransform: url=" + url.toString());
request.setActionURL(URL.encode(url.toString()));
}
}
If I can find out how to get the UserDTO as JSON into the requestBody, I think I will have solved all my issues. For extra information you should know, I am using Spring 3.2 and the Jackson Message Converters configured in the springmvc-servlet.xml file.
At one point I did see all the data getting appended to the URL, but I would prefer if the data was not in the URL as parameters, but rather in the request body. SO, I need to know if this is possible, and how to do it.
Thanks for any help!!!
You probably want to undo all of these modifications and just implement the default RestDataSource protocol, which already passes the request body as JSON if you just call RestDataSource.setDataFormat(). There are sample JSON messages in the docs:
http://www.smartclient.com/smartgwtee/javadoc/com/smartgwt/client/data/RestDataSource.html
Among other problems you've created:
the different CRUD operations now go to distinct URLs and use different HTTP verbs, so they can no longer be combined into a single queue and sent together. This means you can't do basic things like perform a mixture of create and update operations together in a transaction, save a new Order along with it's OrderItems, or save data and also fetch dependent data needed to transition to a new screen.
you're assuming the "fetch" will be based on HTTP GET, but this requires awkward encoding of nested criteria structures (AdvancedCriteria) into URL parameters, which can easily hit the maximum URL length
For these and other reasons, most generated Java services do not meet the needs of a modern UI, and the auto-generation approach should not be used. Deeper explanation in the FAQ:
http://forums.smartclient.com/showthread.php?t=8159#aExistingRest
I am working on an Eclipse plugin and am faced with checked exceptions thrown from the API that I am using in my plugin. What is the practice around handling such exceptions in the context of a plugin? I could not find an appropriate Exception subclass from the Plugin development API.
Thanks in advance.
I use logging classes that I found in a book titled "Eclipse Plug-ins", by Eric Clayberg and Dan Rubel.
Here's the main logging class.
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
public class EclipseLogging {
public static void logInfo(Plugin plugin, String pluginID, String message,
boolean display) {
log(plugin, pluginID, IStatus.INFO, IStatus.OK, message, null, display);
}
public static void logInfo(Plugin plugin, String pluginID,
Throwable exception) {
log(plugin, createStatus(pluginID, IStatus.ERROR, IStatus.OK,
"Unexpected Exception", exception));
}
public static void logInfo(Plugin plugin, String pluginID, String message,
Throwable exception) {
log(plugin, createStatus(pluginID, IStatus.ERROR, IStatus.OK, message,
exception));
}
public static void logError(Plugin plugin, String pluginID,
Throwable exception) {
logError(plugin, pluginID, "Unexpected Exception", exception);
}
public static void logError(Plugin plugin, String pluginID, String message,
Throwable exception) {
log(plugin, pluginID, IStatus.ERROR, IStatus.OK, message, exception,
true);
}
public static void log(Plugin plugin, String pluginID, int severity,
int code, String message, Throwable exception, boolean display) {
if (display) {
ExceptionAction action = new ExceptionAction(plugin, message,
exception);
action.run();
}
log(plugin, createStatus(pluginID, severity, code, message, exception));
}
public static IStatus createStatus(String pluginID, int severity, int code,
String message, Throwable exception) {
return new Status(severity, pluginID, code, message, exception);
}
public static void log(Plugin plugin, IStatus status) {
plugin.getLog().log(status);
}
}
And here's the exception action class.
import org.eclipse.core.runtime.Plugin;
import org.eclipse.jface.action.Action;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
public class ExceptionAction extends Action {
private Plugin plugin;
private String message;
private Throwable exception;
public ExceptionAction(Plugin plugin, String message, Throwable exception) {
this.plugin = plugin;
this.message = message;
this.exception = exception;
}
public void run() {
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
if (window != null) {
Shell parentShell = window.getShell();
parentShell.forceActive();
try {
ExceptionDetailsDialog dialog = new ExceptionDetailsDialog(
parentShell, null, null, message, exception, plugin);
dialog.open();
} catch (SWTException e) {
}
}
}
}
And finally, the classes to display the exception.
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
/**
* An abstract dialog with a details section that can be shown or hidden by the
* user. Subclasses are responsible for providing the content of the details
* section.
*/
public abstract class AbstractDetailsDialog extends Dialog {
private final String title;
private final String message;
private final Image image;
private Button detailsButton;
private Control detailsArea;
private Point cachedWindowSize;
/**
* Construct a new instance with the specified elements. Note that the
* window will have no visual representation (no widgets) until it is told
* to open. By default, <code>open</code> blocks for dialogs.
*
* #param parentShell
* the parent shell, or <code>null</code> to create a top-level
* shell
* #param title
* the title for the dialog or <code>null</code> for none
* #param image
* the image to be displayed
* #param message
* the message to be displayed
*/
public AbstractDetailsDialog(Shell parentShell, String title, Image image,
String message) {
this(new SameShellProvider(parentShell), title, image, message);
}
/**
* Construct a new instance with the specified elements. Note that the
* window will have no visual representation (no widgets) until it is told
* to open. By default, <code>open</code> blocks for dialogs.
*
* #param parentShell
* the parent shell provider (not <code>null</code>)
* #param title
* the title for the dialog or <code>null</code> for none
* #param image
* the image to be displayed
* #param message
* the message to be displayed
*/
public AbstractDetailsDialog(IShellProvider parentShell, String title,
Image image, String message) {
super(parentShell);
this.title = title;
this.image = image;
this.message = message;
setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL);
}
/**
* Configures the given shell in preparation for opening this window in it.
* In our case, we set the title if one was provided.
*/
protected void configureShell(Shell shell) {
super.configureShell(shell);
if (title != null)
shell.setText(title);
}
/**
* Creates and returns the contents of the upper part of this dialog (above
* the button bar). This includes an image, if specified, and a message.
*
* #param parent
* the parent composite to contain the dialog area
* #return the dialog area control
*/
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
if (image != null) {
((GridLayout) composite.getLayout()).numColumns = 2;
Label label = new Label(composite, 0);
image.setBackground(label.getBackground());
label.setImage(image);
label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER
| GridData.VERTICAL_ALIGN_BEGINNING));
}
Label label = new Label(composite, SWT.WRAP);
if (message != null)
label.setText(message);
GridData data = new GridData(GridData.FILL_HORIZONTAL
| GridData.VERTICAL_ALIGN_CENTER);
data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
label.setLayoutData(data);
label.setFont(parent.getFont());
return composite;
}
/**
* Adds OK and Details buttons to this dialog's button bar.
*
* #param parent
* the button bar composite
*/
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
false);
detailsButton = createButton(parent, IDialogConstants.DETAILS_ID,
IDialogConstants.SHOW_DETAILS_LABEL, false);
}
/**
* The buttonPressed() method is called when either the OK or Details
* buttons is pressed. We override this method to alternately show or hide
* the details area if the Details button is pressed.
*/
protected void buttonPressed(int id) {
if (id == IDialogConstants.DETAILS_ID)
toggleDetailsArea();
else
super.buttonPressed(id);
}
/**
* Toggles the unfolding of the details area. This is triggered by the user
* pressing the Details button.
*/
protected void toggleDetailsArea() {
Point oldWindowSize = getShell().getSize();
Point newWindowSize = cachedWindowSize;
cachedWindowSize = oldWindowSize;
// Show the details area.
if (detailsArea == null) {
detailsArea = createDetailsArea((Composite) getContents());
detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL);
}
// Hide the details area.
else {
detailsArea.dispose();
detailsArea = null;
detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL);
}
/*
* Must be sure to call getContents().computeSize(SWT.DEFAULT,
* SWT.DEFAULT) before calling getShell().setSize(newWindowSize) since
* controls have been added or removed.
*/
// Compute the new window size.
Point oldSize = getContents().getSize();
Point newSize = getContents().computeSize(SWT.DEFAULT, SWT.DEFAULT);
if (newWindowSize == null)
newWindowSize = new Point(oldWindowSize.x, oldWindowSize.y
+ (newSize.y - oldSize.y));
// Crop new window size to screen.
Point windowLoc = getShell().getLocation();
Rectangle screenArea = getContents().getDisplay().getClientArea();
final int pos = screenArea.height - (windowLoc.y - screenArea.y);
if (newWindowSize.y > pos)
newWindowSize.y = pos;
getShell().setSize(newWindowSize);
((Composite) getContents()).layout();
}
/**
* subclasses must implement createDetailsArea to provide content for the
* area of the dialog made visible when the Details button is clicked.
*
* #param parent
* the details area parent
* #return the details area
*/
protected abstract Control createDetailsArea(Composite parent);
}
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.Dictionary;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
* A dialog to display one or more errors to the user, as contained in an
* <code>IStatus</code> object along with the plug-in identifier, name, version
* and provider. If an error contains additional detailed information then a
* Details button is automatically supplied, which shows or hides an error
* details viewer when pressed by the user.
*
* #see org.eclipse.core.runtime.IStatus
*/
public class ExceptionDetailsDialog extends AbstractDetailsDialog {
/**
* The details to be shown ({#link Exception}, {#link IStatus}, or
* <code>null</code> if no details).
*/
private final Object details;
/**
* The plugin triggering this details dialog and whose information is to be
* shown in the details area or <code>null</code> if no plugin details
* should be shown.
*/
private final Plugin plugin;
/**
* Construct a new instance with the specified elements. Note that the
* window will have no visual representation (no widgets) until it is told
* to open. By default, <code>open</code> blocks for dialogs.
*
* #param parentShell
* the parent shell, or <code>null</code> to create a top-level
* shell
* #param title
* the title for the dialog or <code>null</code> for none
* #param image
* the image to be displayed
* #param message
* the message to be displayed
* #param details
* an object whose content is to be displayed in the details
* area, or <code>null</code> for none
* #param plugin
* The plugin triggering this deatils dialog and whose
* information is to be shown in the details area or
* <code>null</code> if no plugin details should be shown.
*/
public ExceptionDetailsDialog(Shell parentShell, String title, Image image,
String message, Object details, Plugin plugin) {
this(new SameShellProvider(parentShell), title, image, message,
details, plugin);
}
/**
* Construct a new instance with the specified elements. Note that the
* window will have no visual representation (no widgets) until it is told
* to open. By default, <code>open</code> blocks for dialogs.
*
* #param parentShell
* the parent shell provider (not <code>null</code>)
* #param title
* the title for the dialog or <code>null</code> for none
* #param image
* the image to be displayed
* #param message
* the message to be displayed
* #param details
* an object whose content is to be displayed in the details
* area, or <code>null</code> for none
* #param plugin
* The plugin triggering this deatils dialog and whose
* information is to be shown in the details area or
* <code>null</code> if no plugin details should be shown.
*/
public ExceptionDetailsDialog(IShellProvider parentShell, String title,
Image image, String message, Object details, Plugin plugin) {
super(parentShell, getTitle(title, details), getImage(image, details),
getMessage(message, details));
this.details = details;
this.plugin = plugin;
}
/**
* Build content for the area of the dialog made visible when the Details
* button is clicked.
*
* #param parent
* the details area parent
* #return the details area
*/
protected Control createDetailsArea(Composite parent) {
// Create the details area.
Composite panel = new Composite(parent, SWT.NONE);
panel.setLayoutData(new GridData(GridData.FILL_BOTH));
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
panel.setLayout(layout);
// Create the details content.
createProductInfoArea(panel);
createDetailsViewer(panel);
return panel;
}
/**
* Create fields displaying the plugin information such as name, identifer,
* version and vendor. Do nothing if the plugin is not specified.
*
* #param parent
* the details area in which the fields are created
* #return the product info composite or <code>null</code> if no plugin
* specified.
*/
protected Composite createProductInfoArea(Composite parent) {
// If no plugin specified, then nothing to display here
if (plugin == null)
return null;
Composite composite = new Composite(parent, SWT.NULL);
composite.setLayoutData(new GridData());
GridLayout layout = new GridLayout();
layout.numColumns = 2;
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
composite.setLayout(layout);
Dictionary<?, ?> bundleHeaders = plugin.getBundle().getHeaders();
String pluginId = plugin.getBundle().getSymbolicName();
String pluginVendor = (String) bundleHeaders.get("Bundle-Vendor");
String pluginName = (String) bundleHeaders.get("Bundle-Name");
String pluginVersion = (String) bundleHeaders.get("Bundle-Version");
new Label(composite, SWT.NONE).setText("Provider:");
new Label(composite, SWT.NONE).setText(pluginVendor);
new Label(composite, SWT.NONE).setText("Plug-in Name:");
new Label(composite, SWT.NONE).setText(pluginName);
new Label(composite, SWT.NONE).setText("Plug-in ID:");
new Label(composite, SWT.NONE).setText(pluginId);
new Label(composite, SWT.NONE).setText("Version:");
new Label(composite, SWT.NONE).setText(pluginVersion);
return composite;
}
/**
* Create the details field based upon the details object. Do nothing if the
* details object is not specified.
*
* #param parent
* the details area in which the fields are created
* #return the details field
*/
protected Control createDetailsViewer(Composite parent) {
if (details == null)
return null;
Text text = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER
| SWT.H_SCROLL | SWT.V_SCROLL);
text.setLayoutData(new GridData(GridData.FILL_BOTH));
// Create the content.
StringWriter writer = new StringWriter(1000);
if (details instanceof Throwable)
appendException(new PrintWriter(writer), (Throwable) details);
else if (details instanceof IStatus)
appendStatus(new PrintWriter(writer), (IStatus) details, 0);
text.setText(writer.toString());
return text;
}
// /////////////////////////////////////////////////////////////////
//
// Utility methods for building content
//
// /////////////////////////////////////////////////////////////////
/**
* Answer the title based on the provided title and details object.
*/
public static String getTitle(String title, Object details) {
if (title != null)
return title;
if (details instanceof Throwable) {
Throwable e = (Throwable) details;
while (e instanceof InvocationTargetException)
e = ((InvocationTargetException) e).getTargetException();
String name = e.getClass().getName();
return name.substring(name.lastIndexOf('.') + 1);
}
return "Exception";
}
/**
* Answer the image based on the provided image and details object.
*/
public static Image getImage(Image image, Object details) {
if (image != null)
return image;
Display display = Display.getCurrent();
if (details instanceof IStatus) {
switch (((IStatus) details).getSeverity()) {
case IStatus.ERROR:
return display.getSystemImage(SWT.ICON_ERROR);
case IStatus.WARNING:
return display.getSystemImage(SWT.ICON_WARNING);
case IStatus.INFO:
return display.getSystemImage(SWT.ICON_INFORMATION);
case IStatus.OK:
return null;
}
}
return display.getSystemImage(SWT.ICON_ERROR);
}
/**
* Answer the message based on the provided message and details object.
*/
public static String getMessage(String message, Object details) {
if (details instanceof Throwable) {
Throwable e = (Throwable) details;
while (e instanceof InvocationTargetException)
e = ((InvocationTargetException) e).getTargetException();
if (message == null)
return e.toString();
return MessageFormat.format(message, new Object[] { e.toString() });
}
if (details instanceof IStatus) {
String statusMessage = ((IStatus) details).getMessage();
if (message == null)
return statusMessage;
return MessageFormat
.format(message, new Object[] { statusMessage });
}
if (message != null)
return message;
return "An Exception occurred.";
}
public static void appendException(PrintWriter writer, Throwable ex) {
if (ex instanceof CoreException) {
appendStatus(writer, ((CoreException) ex).getStatus(), 0);
writer.println();
}
appendStackTrace(writer, ex);
if (ex instanceof InvocationTargetException)
appendException(writer, ((InvocationTargetException) ex)
.getTargetException());
}
public static void appendStatus(PrintWriter writer, IStatus status,
int nesting) {
for (int i = 0; i < nesting; i++)
writer.print(" ");
writer.println(status.getMessage());
IStatus[] children = status.getChildren();
for (int i = 0; i < children.length; i++)
appendStatus(writer, children[i], nesting + 1);
}
public static void appendStackTrace(PrintWriter writer, Throwable ex) {
ex.printStackTrace(writer);
}
}
I'm using this to send a htlm file direclty to printer and it says invalid flavour which means that the printer does not support the formats. Any one have an idea to do this..
/**
* #param args
*/
public static void main(String[] args) {
// Input the file
FileInputStream textStream = null;
try {
textStream = new FileInputStream("./some.html");
} catch (FileNotFoundException ffne) {
}
if (textStream == null) {
return;
}
// Set the document type
DocFlavor myFormat = DocFlavor.INPUT_STREAM.TEXT_HTML_HOST;
// Create a Doc
Doc myDoc = new SimpleDoc(textStream, myFormat , null);
// Build a set of attributes
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(new Copies(1));
//aset.add(MediaSize.NA.LEGAL);
aset.add(Sides.ONE_SIDED);
// discover the printers that can print the format according to the
// instructions in the attribute set
PrintService services = PrintServiceLookup.lookupDefaultPrintService();
//PrintServiceLookup.lookupPrintServices(myFormat, aset);
// Create a print job from one of the print services
//System.out.println("====5======="+service.get);
//if (services.length > 0) {
for (int i = 0; i < services.getSupportedDocFlavors().length; i++) {
System.out.println("====getSupportedDocFlavors======="+services.getSupportedDocFlavors()[i]);
}
DocPrintJob job = services.createPrintJob();
try {
job.print(myDoc, aset);
} catch (PrintException pe) {
System.out.println("====PrintException======="+pe);
}
//}
}
It says
sun.print.PrintJobFlavorException: invalid flavor
You are trying to force printer to handle (render) HTML document onto the paper. It will never work that way. And ofcourse the flavor you are sending is not supported.
First of all you need to render HTML into some graphical representation and then send it to printer. There are no good cross-platform tools for Java that could render modern HTML pages. But there is one in JavaFX and i guess you could use it to handle the task.
About printing the final image you can read here:
http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-Printing.html
or see the code here:
http://www.java2s.com/Code/Java/2D-Graphics-GUI/PrintanImagetoprintdirectly.htm
or just find any other resource - there are a lot about printing.
public class POSPrinter {
private static final Log LOG = LogFactory.getLog(POSPrinter.class);
public POSPrinter(Long billID, String printMode) {
}
/**
*
* This method prints the specified PDF to specified printer under specified
*
* job name
*
*
*
* #param filePath
* Path of PDF file
*
* #param printerName
* Printer name
*
* #param jobName
* Print job name
*
* #throws IOException
*
* #throws PrinterException
*/
public void printPDF(String filePath, String printerName, String jobName,
Integer height, Integer width) throws IOException, PrinterException {
FileInputStream fileInputStream = new FileInputStream(filePath);
byte[] pdfContent = new byte[fileInputStream.available()];
fileInputStream.read(pdfContent, 0, fileInputStream.available());
ByteBuffer buffer = ByteBuffer.wrap(pdfContent);
final PDFFile pdfFile = new PDFFile(buffer);
Printable printable = new Printable() {
public int print(Graphics graphics, PageFormat pageFormat,
int pageIndex) throws PrinterException {
int pagenum = pageIndex + 1;
if ((pagenum >= 1) && (pagenum <= pdfFile.getNumPages())) {
Graphics2D graphics2D = (Graphics2D) graphics;
PDFPage page = pdfFile.getPage(pagenum);
Rectangle imageArea = new Rectangle(
(int) pageFormat.getImageableX(),
(int) pageFormat.getImageableY(),
(int) pageFormat.getImageableWidth(),
(int) pageFormat.getImageableHeight());
graphics2D.translate(0, 0);
PDFRenderer pdfRenderer = new PDFRenderer(page, graphics2D,
imageArea, null, null);
try {
page.waitForFinish();
pdfRenderer.run();
} catch (InterruptedException exception) {
exception.printStackTrace();
}
return PAGE_EXISTS;
} else {
return NO_SUCH_PAGE;
}
}
};
PrinterJob printJob = PrinterJob.getPrinterJob();
PageFormat pageFormat = PrinterJob.getPrinterJob().defaultPage();
printJob.setJobName(jobName);
Book book = new Book();
book.append(printable, pageFormat, pdfFile.getNumPages());
printJob.setPageable(book);
Paper paper = new Paper();
paper.setSize(width, height);
paper.setImageableArea(0, 0, paper.getWidth(), paper.getHeight());
// pageFormat
pageFormat.setPaper(paper);
// PrintService[] printServices = PrinterJob.lookupPrintServices();
//
// for (int count = 0; count < printServices.length; ++count) {
//
// if (printerName.equalsIgnoreCase(printServices[count].getName())) {
//
// printJob.setPrintService(printServices[count]);
//
// break;
//
// }
//
// }
PrintService printService = PrintServiceLookup
.lookupDefaultPrintService();
printJob.setPrintService(printService);
printJob.print();
}