I'm using spring-data-solr and have data import handler(DIH) in solr. How can I call DIH by repository or SolrTemplate, or some else?
I'd recommend a Custom Respository using SolrCallback to execute desired request.
#Override
public SolrResponse dataImport(final String command) {
return solrTemplate.execute(new SolrCallback<SolrResponse>() {
#Override
public SolrResponse doInSolr(SolrServer solrServer) throws SolrServerException, IOException {
return new SolrRequest(METHOD.GET, "/dataimport?command=" + command) {
//..skipped some methods to shorten
#Override
public SolrResponse process(SolrServer server) throws SolrServerException, IOException {
SolrResponseBase response = new SolrResponseBase();
response.setResponse(server.request(this));
return response;
}
}.process(solrServer);
}
});
}
If someone else is struggling to get the DIH working in the current version (Solr 8.11) - this is what worked for me (be sure to adapt the core name):
solrTemplate.execute(new SolrCallback<SolrResponse>() {
#Override
public SolrResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException {
SolrRequest<SolrResponse> solrRequest = new SolrRequest<>(SolrRequest.METHOD.GET, "/<core_name>/dataimport?command=full-import&commit=true&clean=true") {
#Override
public SolrParams getParams() {
return null;
}
#Override
protected SolrResponse createResponse(SolrClient solrClient) {
SolrResponseBase response = new SolrResponseBase();
try {
response.setResponse(solrClient.request(this));
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
return response;
}
};
solrRequest.setResponseParser(new DelegationTokenResponse.JsonMapResponseParser());
return solrRequest.process(solrClient);
}
});
Related
I'm new on Android development and I'm learning how to use MVP pattern correctly in recently.
Now I'm facing a tricky problem, hope can get some helpful suggestion or solution from here.
First, here is my presenter
public class MVPPresenter {
private MVPView mvpView;
public MVPPresenter(MVPView mvpView) {
this.mvpView = mvpView;
}
public void loadData() {
mvpView.startLoading();
final List<MVPModel> list = new ArrayList<>();
//the part that I trying to extract starts here.
Call call = DataRetriever.getDataByGet(URLCombiner.GET_FRONT_PAGE_ITEMS);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
mvpView.errorLoading();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try {
JSONObject result = new JSONObject(response.body().string());
int errorCode = result.getInt("ErrorCode");
if (errorCode == 0) {
JSONArray value = result.getJSONObject("Value").getJSONArray("hot");
for (int i = 0; i < value.length(); i++) {
MVPModel mvpModel = new MVPModel();
String name = null;
String image = null;
try {
name = value.getJSONObject(i).getString("title");
image = URLCombiner.IP + value.getJSONObject(i).getString("pic");
} catch (JSONException e) {
e.printStackTrace();
}
mvpModel.setName(name);
mvpModel.setImage(image);
list.add(mvpModel);
}
if (list.size() > 0) {
mvpView.successLoading(list);
mvpView.finishLoading();
} else {
mvpView.errorLoading();
}
} else {
mvpView.errorLoading();
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
mvpView.errorLoading();
}
}
});
//the part that I trying to extract ends here.
}
}
As you can see, I'm trying to extract the part which is using OKHttp libs into a class (I call it data manager) which I hope it can handle every task between server and client. But here's the thing, when I trying to pass the result from the data manager to presenter, I got NullPointException because of the async mechanism.
I would like to know how to passing the data, which is come from server in async, to the presenter when the data has finish downloading.
And here's my ideal data manager, I know this might looks stupid but I think this can make my problem more clearly.
public class LoadServerData {
private static JSONArray arrayData = new JSONArray();
public static JSONArray getServerData() {
Call call = DataRetriever.getDataByGet(URLCombiner.GET_FRONT_PAGE_ITEMS);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try {
JSONObject result = new JSONObject(response.body().string());
int errorCode = result.getInt("ErrorCode");
if (errorCode == 0) {
arrayData = result.getJSONObject("Value").getJSONArray("hot"); //the data I would like to return.
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
return arrayData; //this is gonna be an empty data.
}
}
I've reading some article that might can solve my problem, but still not getting any fine answer. Perhaps I've using wrong keyword I think. Hopes you guys can give me some ideas or solutions to help me or inspire me.
P.S. version of OKhttp libs is 3.7.0
Create a simple Listener so it can be called whenever the server call finishes:
public class LoadServerData {
public static interface Listener {
public void onSuccess(JSONArray data);
public void onError(Exception error);
}
public static void getServerData(Listener listener) {
Call call = DataRetriever.getDataByGet(URLCombiner.GET_FRONT_PAGE_ITEMS);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
listener.onError(e);
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try {
JSONObject result = new JSONObject(response.body().string());
int errorCode = result.getInt("ErrorCode");
if (errorCode == 0) {
JSONArray arrayData = result.getJSONObject("Value").getJSONArray("hot"); //the data I would like to return.
listener.onSuccess(arrayData);
} else {
listener.onError(...);
}
} catch (JSONException e) {
e.printStackTrace();
listener.onError(e);
}
} else {
listener.onError(...);
}
}
});
}
}
I have created an application which reads & writes into a remote file. I have different files (A.properties, B.properties, C.properties) in different directories (folder-1, folder-2, folder-3). Each directory has the same filename with different data.
I have implemented concurrency in my application by using the LockRegistry provided by this other answer. The issue is that if a thread is accessing A.properties while another thread accesses B.properties, the propertyMap displayed to the end user will contain both data from property files. How can I resolve this issue?
My code:
public class UDEManager
{
private Map<String, String> propertyMap = new TreeMap<>();
HttpSession session = null;
public UDEPropertyManager()
{
super();
}
public void init(ServletConfig config) throws ServletException
{
super.init(config);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// Code for calling thread for read/write operations into remote
// file and fill the propertyMap
}
}
class WebAppProperty implements Runnable
{
private WebApp webapp; // folder-1
private String propertyFile; // A.properties
private String keyValue; //messages-title=Messages
private LockType mode;
public String getPropertyFile()
{
return propertyFile;
}
public void setPropertyFile(String propertyFile)
{
this.propertyFile = propertyFile;
}
#Override
public void run()
{
try {
LockRegistry.INSTANCE.acquire(propertyFile, mode);
if (this.mode == LockType.WRITE) {
writeToPropertyFile();
} else if (this.mode == LockType.READ) {
getProperty(this.webapp, this.propertyFile);
}
} catch (Exception ie) {
sysoutAndLog("Thread is Interrupted");
ie.printStackTrace();
} finally {
LockRegistry.INSTANCE.release(propertyFile, mode);
}
}
private boolean getProperty(WebApp webapp, String property)
{
try {
// read from file and put it into Map instance variable
// of calling class (UDEManager)
propertyMap.put(key, value);
} catch(Exception e) {
sysoutAndLog("Error while reading property ");
e.printStackTrace();
}
return false;
}
private void writeToPropertyFile()
{
try {
// Write data into remote file
} catch (Exception e) {
sysoutAndLog("exception while writing to file.");
e.printStackTrace();
}
}
}
You should associate the properties map with the user session or request
I have a servlet filter that intercepts requests and checks for a custom "encrypted" header:
public class EncryptionFilter extends GenericFilterBean{
#Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) {
final HttpServletRequest httpRequest = (HttpServletRequest) request;
if (httpRequest.getHeader("EncryptedCommunication") != null){
decryptedRequest = /*decrypt request body and forward to next filter*/
encryptedResponse = /*encrypt request body and forward to next filter*/
filterChain.doFilter(decryptedRequest, encryptedResponse);
}
else { /* communication not encrypted */
filterChain.doFilter(request, response);
}
}
}
When the header exist I should decrypt the request body and also encrypt the response body.
Otherwise, should leave the request/response body unchanged.
How can I change the response only when needed?
You need to use a HttpServletResponseWrapper example is :
filterChain.doFilter(servletRequest,
new HttpServletResponseWrapper((HttpServletResponse) servletResponse) {
#Override
public void setHeader(String name, String value) {
if (!HTTPCacheHeader.ETAG.getName().equalsIgnoreCase(name)) {
super.setHeader(name, value);
}
}
});
See http://www.programcreek.com/java-api-examples/javax.servlet.http.HttpServletResponseWrapper
This is an example of how the body can be set :
public class ReadTwiceHttpServletRequestWrapper extends HttpServletRequestWrapper {
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public ReadTwiceHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
try {
IOUtils.copy(request.getInputStream(), outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(outputStream.toByteArray())));
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
return new ServletInputStream() {
#Override
public int readLine(byte[] b, int off, int len) throws IOException {
return inputStream.read(b, off, len);
}
#Override
public boolean isFinished() {
return inputStream.available() > 0;
}
#Override
public boolean isReady() {
return true;
}
#Override
public void setReadListener(ReadListener arg0) {
// TODO Auto-generated method stub
}
#Override
public int read() throws IOException {
return inputStream.read();
}
};
}
public void setBody(String body) {
outputStream = new ByteArrayOutputStream();
try {
outputStream.write(body.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getBody() {
return new String(outputStream.toByteArray());
}
See How to get the XML from POST request and modify it in Servlet Filter?
I updated the CodenameOne Plugin for NetBeans and since then every connection produces the error below
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.util.Hashtable
at com.codename1.impl.CodenameOneImplementation.getCookiesForURL(CodenameOneImplementation.java:3934)
at com.codename1.io.ConnectionRequest.performOperation(ConnectionRequest.java:308)
at com.codename1.io.NetworkManager$NetworkThread.run(NetworkManager.java:263)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
Connection for push notifications registration even produces this error.
Any help?
The issue came in because I stored, deleted and restored "Cookies" storage object in some of my ConnectionRequest calls. I should have just set ConnectionRequest's setCookiesEnabled method to false.
Bad code used
try {
ConnectionRequest connectionRequest = new ConnectionRequest() {
#Override
protected void initConnection(Object connection) {
super.initConnection(connection);
storeAndDeleteUserCookiesData();
}
#Override
protected void readResponse(InputStream input) throws IOException {
}
#Override
protected void postResponse() {
restoreCookies();
}
#Override
protected void handleException(Exception err) {
restoreCookies();
}
#Override
protected void handleErrorResponseCode(int code, String message) {
restoreCookies();
}
#Override
public void retry() {
super.retry();
}
};
NetworkManager.getInstance().addToQueue(connectionRequest);
} catch (Exception ex) {
restoreCookies();
}
protected void storeAndDeleteUserCookiesData() {
if (Storage.getInstance().exists("Cookies")) {
Storage.getInstance().writeObject("Cookies_" + appName, Storage.getInstance().exists("Cookies"));
Storage.getInstance().deleteStorageFile("Cookies");
}
Storage.getInstance().clearCache();
}
protected void restoreCookies() {
Storage.getInstance().writeObject("Cookies", Storage.getInstance().readObject("Cookies_" + appName));
Storage.getInstance().clearCache();
}
The fix was
ConnectionRequest connectionRequest = new ConnectionRequest() {
};
connectionRequest.setCookiesEnabled(false);
I asked a question regarding HTTP Upgrade handling in Servlet 3.1 on wildfly-dev mailing list how to develop simple bi-directional full-duplex echo protocol. After few days of discussion we concluded that the following example is somewhat correct:
#WebServlet(urlPatterns = "/upgrade")
public class AsyncEchoUpgradeServlet extends HttpServlet {
private static final long serialVersionUID = -6955518532146927509L;
#Override
protected void doGet(final HttpServletRequest req,
final HttpServletResponse resp) throws ServletException, IOException {
req.upgrade(Handler.class);
}
public static class Handler implements HttpUpgradeHandler {
#Override
public void init(final WebConnection wc) {
Listener listener = new Listener(wc);
try {
// we have to set the write listener before the read listener
// otherwise the output stream could be written to before it is
// in async mode
wc.getOutputStream().setWriteListener(listener);
wc.getInputStream().setReadListener(listener);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
#Override
public void destroy() {
}
}
private static class Listener implements WriteListener, ReadListener {
private final WebConnection connection;
private final Queue<String> queue = new ArrayDeque<String>();
private Listener(final WebConnection connection) {
this.connection = connection;
}
#Override
publicvoid onDataAvailable() throws IOException {
byte[] data = new byte[100];
while (connection.getInputStream().isReady()) {
int read;
if ((read = connection.getInputStream().read(data)) != -1) {
queue.add(new String(data, 0, read));
}
onWritePossible();
}
}
#Override
public void onAllDataRead() throws IOException {
}
#Override
public void onWritePossible() throws IOException {
while (!queue.isEmpty() && connection.getOutputStream().isReady()) {
String data = queue.poll();
connection.getOutputStream().write(data.getBytes());
}
}
#Override
public void onError(final Throwable t) {
}
}
}
It actually works and it is the only example exchanged during our discussion that works well and we don't have to create any additional threads to handle both input and output.
What bothers me in this example is that we call explicitly onWritePossible() from within onDataAvailable().
Does anyone have any other example on HTTP Upgrade using Servlet 3.1 API? Is the example shown above correct?